Browse Source

new code for .measurement

pre-master-46
h_vogt 17 years ago
parent
commit
9f1ee290a4
  1. 2
      src/frontend/Makefile.am
  2. 624
      src/frontend/com_measure2.c
  3. 7
      src/frontend/com_measure2.h
  4. 36
      src/frontend/dotcards.c
  5. 1
      src/frontend/dotcards.h
  6. 592
      src/frontend/measure.c
  7. 1
      src/frontend/numparam/numparam.h
  8. 19
      src/frontend/numparam/xpressn.c
  9. 1
      src/include/bool.h
  10. 12
      src/include/macros.h
  11. 4
      src/misc/Makefile.am
  12. 5
      src/tclspice.c
  13. 4
      visualc/vngspice.sln
  14. 30
      visualc/vngspice.vcproj

2
src/frontend/Makefile.am

@ -95,6 +95,8 @@ libfte_la_SOURCES = \
breakp2.h \
circuits.c \
circuits.h \
compatmode.c \
compatmode.h \
cpitf.c \
cpitf.h \
define.c \

624
src/frontend/com_measure2.c

@ -1,7 +1,7 @@
/* New routines to evaluate the .measure cards.
Entry point is function get_measure2(), called by fcn do_measure()
from measure.c, if line measure.c:25 is commented out.
Patches by Bill Swartz from 2009-05-18 are included.
Patches by Bill Swartz from 2009-05-18 and 2009-08-21 are included.
$Id$
*/
@ -14,12 +14,9 @@
#include "vectors.h"
#include <math.h>
#include "dotcards.h"
#include "com_measure2.h"
#ifdef _MSC_VER
#define strcasecmp _stricmp
#endif
typedef enum {
MEASUREMENT_OK = 0,
MEASUREMENT_FAILURE = 1
@ -33,42 +30,225 @@ typedef struct measure
char *result;
char *m_vec; // name of the output variable which determines the beginning of the measurement
char *m_vec2;
int m_rise;
int m_fall;
int m_cross;
char *m_vec2; // second output variable to measure if applicable
int m_rise; // count number of rise events
int m_fall; // count number of fall events
int m_cross; // count number of rise/fall aka cross events
double m_val; // value of the m_ver at which the counter for crossing, rises or falls is incremented by one
double m_td; // amount of delay before the measurement should start
double m_from;
double m_to;
double m_at;
double m_measured;
double m_measured_at;
double m_from; // measure only in a time window - starting time of window
double m_to; // measurement window - ending time
double m_at; // measure at the specified time
double m_measured; // what we measured
double m_measured_at; //* what we measured at the given time
} measure;
} MEASURE, *MEASUREPTR ;
enum AnalysisType {
AT_DELAY, AT_TRIG,
typedef enum AnalysisType {
AT_UNKNOWN, AT_DELAY, AT_TRIG,
AT_FIND, AT_WHEN,
AT_AVG, AT_MIN, AT_MAX, AT_RMS, AT_PP,
AT_INTEG, AT_DERIV,
AT_ERR, AT_ERR1, AT_ERR2, AT_ERR3
};
} ANALYSIS_TYPE_T ;
/** return precision (either 5 or value of environment variable NGSPICE_MEAS_PRECISION) */
int get_measure_precision(void)
int
measure_get_precision(void)
{
char *env_ptr;
int precision = 5;
if ( ( env_ptr = getenv("NGSPICE_MEAS_PRECISION") ) ) {
precision = atoi(env_ptr);
}
return precision;
char *env_ptr;
int precision = 5;
if ( ( env_ptr = getenv("NGSPICE_MEAS_PRECISION") ) ) {
precision = atoi(env_ptr);
}
return precision;
} /* end measure_get_precision() */
void com_measure_when(struct measure *meas) {
static void measure_errMessage(char *mName, char *mFunction, char *trigTarg, char *errMsg, int chk_only)
{
if(!(chk_only)){
printf("\tmeasure '%s' failed\n", mName);
printf("Error: measure %s %s(%s) :\n", mName, mFunction, trigTarg);
printf("\t%s\n",errMsg);
}
return;
} /* end measure_errMessage() */
static double
measure_interpolate( struct dvec *time, struct dvec *values, int i, int j, double var_value, char x_or_y )
{
double slope;
double yint;
double result;
slope = (values->v_realdata[j] - values->v_realdata[i]) /
(time->v_realdata[j] - time->v_realdata[i]);
yint = values->v_realdata[i] - slope*time->v_realdata[i];
if ( x_or_y == 'x' ) result = (var_value - yint)/slope;
else result = slope*var_value + yint;
return result;
} /* end measure_interpolate() */
/* -----------------------------------------------------------------
* Function: Given an operation string returns back the measure type - one of
* the enumerated type ANALSYS_TYPE_T.
* ----------------------------------------------------------------- */
static ANALYSIS_TYPE_T measure_function_type( char *operation )
{
char *mFunction ; /* operation */
ANALYSIS_TYPE_T mFunctionType ; /* type of requested function */
mFunction = cp_unquote(operation);
// Functions
if (strcasecmp(mFunction,"DELAY")==0)
mFunctionType = AT_DELAY;
else if (strcasecmp(mFunction,"TRIG")==0)
mFunctionType = AT_DELAY;
else if (strcasecmp(mFunction,"TARG")==0)
mFunctionType = AT_DELAY;
else if (strcasecmp(mFunction,"FIND")==0)
mFunctionType = AT_FIND;
else if (strcasecmp(mFunction,"WHEN")==0)
mFunctionType = AT_WHEN;
else if (strcasecmp(mFunction,"AVG")==0)
mFunctionType = AT_AVG;
else if (strcasecmp(mFunction,"MIN")==0)
mFunctionType = AT_MIN;
else if (strcasecmp(mFunction,"MAX")==0)
mFunctionType = AT_MAX;
else if (strcasecmp(mFunction,"RMS")==0)
mFunctionType = AT_RMS;
else if (strcasecmp(mFunction,"PP")==0)
mFunctionType = AT_PP;
else if (strcasecmp(mFunction,"INTEG")==0)
mFunctionType = AT_INTEG;
else if (strcasecmp(mFunction,"DERIV")==0)
mFunctionType = AT_DERIV;
else if (strcasecmp(mFunction,"ERR")==0)
mFunctionType = AT_ERR;
else if (strcasecmp(mFunction,"ERR1")==0)
mFunctionType = AT_ERR1;
else if (strcasecmp(mFunction,"ERR2") == 0)
mFunctionType = AT_ERR2;
else if (strcasecmp(mFunction,"ERR3") == 0)
mFunctionType = AT_ERR3;
else
mFunctionType = AT_UNKNOWN;
return( mFunctionType) ;
} /* end measure_function_type() */
/* -----------------------------------------------------------------
* Function: Parse the measurement line and extract any variables in
* the statement and call com_save2 to instantiate the variable as a
* measurement vector in the transient analysis.
* ----------------------------------------------------------------- */
int measure_extract_variables( char *line )
{
/* Various formats for measure statement:
* .MEASURE {DC|AC|TRAN} result TRIG trig_variable VAL=val
* + <TD=td> <CROSS=# | CROSS=LAST> <RISE=#|RISE=LAST> <FALL=#|FALL=LAST>
* + <TRIG AT=time>
* + TARG targ_variable VAL=val
* + <TD=td> <CROSS=# | CROSS=LAST> <RISE=#|RISE=LAST> <FALL=#|FALL=LAST>
* + <TRIG AT=time>
*
* .MEASURE {DC|AC|TRAN} result WHEN out_variable=val
* + <TD=td> <FROM=val> <TO=val>
* + <CROSS=# | CROSS=LAST> <RISE=#|RISE=LAST> <FALL=#|FALL=LAST>
*
* .MEASURE {DC|AC|TRAN} result WHEN out_variable=out_variable2
* + <TD=td> <FROM=val> <TO=val>
* + <CROSS=# | CROSS=LAST> <RISE=#|RISE=LAST> <FALL=#|FALL=LAST>
*
* .MEASURE {DC|AC|TRAN} result FIND out_variable WHEN out_variable2=val
* + <TD=td> <FROM=val> <TO=val>
* + <CROSS=# | CROSS=LAST> <RISE=#|RISE=LAST> <FALL=#|FALL=LAST>
*
* .MEASURE {DC|AC|TRAN} result FIND out_variable WHEN out_variable2=out_variable3
* + <TD=td>
* + <CROSS=# | CROSS=LAST> <RISE=#|RISE=LAST> <FALL=#|FALL=LAST>
*
* .MEASURE {DC|AC|TRAN} result FIND out_variable AT=val
* + <FROM=val> <TO=val>
*
* .MEASURE {DC|AC|TRAN} result {AVG|MIN|MAX|PP|RMS} out_variable
* + <TD=td> <FROM=val> <TO=val>
*
* .MEASURE {DC|AC|TRAN} result INTEG<RAL> out_variable
* + <TD=td> <FROM=val> <TO=val>
*
* .MEASURE {DC|AC|TRAN} result DERIV<ATIVE> out_variable
* + <TD=td> <FROM=val> <TO=val> <AT=val>
*
* .MEASURE {DC|AC|TRAN} result DERIV<ATIVE> out_variable
* + <TD=td> <FROM=val> <TO=val> <AT=val>
* ----------------------------------------------------------------- */
int len ; /* length of string */
int status ; /* return status */
char *item ; /* parsing item */
char *measure ; /* measure keyword */
char *analysis ; /* analysis option */
char *variable ; /* variable to trace */
wordlist *measure_var ; /* wordlist of measurable */
ANALYSIS_TYPE_T op ; /* measure function type */
status = TRUE;
measure = gettok(&line);
if(!(measure)){
return(status) ;
}
analysis = gettok(&line);
if(!(analysis)){
return(status) ;
}
if( (strcasecmp(analysis,"DC")==0) ||
(strcasecmp(analysis,"AC")==0) ||
(strcasecmp(analysis,"TRAN")==0) ){
analysis = copy(analysis) ;
} else {
/* sometimes operation is optional - for now just pick trans */
analysis = copy("TRAN") ;
}
do {
item = gettok(&line) ;
if( item ){
op = measure_function_type(item) ;
if( op != AT_UNKNOWN ){
/* We have a variable/complex variable coming next */
variable = gettok(&line) ;
if( variable ){
len = strlen(item) ;
if( item[len-1] == '=' ){
} else {
measure_var = gettoks(variable) ;
com_save2(measure_var, analysis);
status = FALSE;
}
}
}
}
} while(line && *line) ;
/*
*/
return( status ) ;
} /* end measure_extract_variables() */
/* -----------------------------------------------------------------
* Function: process a WHEN measurement statement which has been
* parsed into a measurement structure.
* ----------------------------------------------------------------- */
static void com_measure_when(
MEASUREPTR meas /* in : parsed measurement structure */
) {
int i, first;
int riseCnt = 0;
@ -129,7 +309,7 @@ void com_measure_when(struct measure *meas) {
crossCnt =1;
}
}
printf("");
fflush( stdout ) ;
}
if (first > 1) {
@ -186,7 +366,15 @@ void com_measure_when(struct measure *meas) {
return;
}
void measure_at(struct measure *meas, double at) {
/* -----------------------------------------------------------------
* Function: process an AT measurement statement which has been
* parsed into a measurement structure. We make sure to interpolate
* the value when appropriate.
* ----------------------------------------------------------------- */
static void measure_at(
MEASUREPTR meas, /* in : parsed "at" data */
double at /* in: time to perform measurement */
) {
int i;
double value, pvalue, svalue, psvalue;
@ -224,13 +412,17 @@ void measure_at(struct measure *meas, double at) {
return;
}
void measure_avg( ) {
// AVG (Average):
// Calculates the area under the 'out_var' divided by the periods of intrest
return;
}
void measure_minMaxAvg( struct measure *meas, int minMax ) {
/* -----------------------------------------------------------------
* Function: process an MIN, MAX, or AVG statement which has been
* parsed into a measurement structure. We should make sure to interpolate
* the value here when we have m_from and m_to constraints * so this
* function is slightly wrong. Need to fix in future rev.
* ----------------------------------------------------------------- */
static void measure_minMaxAvg(
MEASUREPTR meas, /* in : parsed measurement data request */
ANALYSIS_TYPE_T mFunctionType /* in: one of AT_AVG, AT_MIN, AT_MAX */
) {
int i, avgCnt;
struct dvec *d, *dScale;
@ -272,7 +464,7 @@ void measure_minMaxAvg( struct measure *meas, int minMax ) {
first =1;
} else {
switch (minMax) {
switch (mFunctionType) {
case AT_MIN: {
if (value <= mValue) {
mValue = value;
@ -287,53 +479,195 @@ void measure_minMaxAvg( struct measure *meas, int minMax ) {
}
break;
}
case AT_AVG:
case AT_RMS: {
case AT_AVG: {
mValue = mValue + value;
avgCnt ++;
break;
}
default :
fprintf(cp_err, "Error: improper min/max/avg call.\n");
}
}
}
switch (minMax)
switch (mFunctionType)
{
case AT_AVG: {
meas->m_measured = (mValue / avgCnt);
meas->m_measured_at = svalue;
break;
}
case AT_RMS: {
// printf(" mValue %e svalue %e avgCnt %i, ", mValue, svalue, avgCnt);
meas->m_measured = sqrt(mValue) / avgCnt;
meas->m_measured_at = svalue;
break;
}
case AT_MIN:
case AT_MAX: {
meas->m_measured = mValue;
meas->m_measured_at = mValueAt;
break;
}
default :
fprintf(cp_err, "Error: improper min/max/avg call.\n");
}
return;
}
void measure_rms( ) {
/* -----------------------------------------------------------------
* Function: process an RMS or INTEG statement which has been
* parsed into a measurement structure. Here we do interpolate
* the starting and stopping time window so the answer is correct.
* ----------------------------------------------------------------- */
static void measure_rms_integral(
MEASUREPTR meas, /* in : parsed measurement data request */
ANALYSIS_TYPE_T mFunctionType /* in: one of AT_RMS, or AT_INTEG */
) {
int i; /* counter */
int xy_size ; /* # of temp array elements */
struct dvec *d, *time; /* value and time vectors */
float value, tvalue; /* current value and time value */
double *x ; /* temp x array */
double *y ; /* temp y array */
double toVal ; /* to time value */
double *width ; /* temp width array */
double sum1 ; /* first sum */
double sum2 ; /* second sum */
double sum3 ; /* third sum */
int first;
tvalue =0;
meas->m_measured = 0.0e0;
meas->m_measured_at = 0.0e0;
first =0;
d = vec_get(meas->m_vec);
if (d == NULL) {
fprintf(cp_err, "Error: no such vector as %s.\n", meas->m_vec);
return;
}
time = vec_get("time");
if (time == NULL) {
fprintf(cp_err, "Error: no such vector as time.\n");
return;
}
// Allocate buffers for calculation.
x = (double *) tmalloc(time->v_length * sizeof(double));
y = (double *) tmalloc(time->v_length * sizeof(double));
width = (double *) tmalloc(time->v_length * sizeof(double));
xy_size = 0 ;
toVal = -1 ;
// create new set of values over interval [from, to] -- interpolate if necessary
for (i=0; i < d->v_length; i++) {
value = d->v_realdata[i];
tvalue = time->v_realdata[i];
if (tvalue < meas->m_from)
continue;
if ((meas->m_to != 0.0e0) && (tvalue > meas->m_to) ){
// interpolate ending value if necessary.
if (!(AlmostEqualUlps( tvalue, meas->m_to, 100))){
value = measure_interpolate( time, d, i-1, i, meas->m_to, 'y' );
tvalue = meas->m_to ;
}
x[xy_size] = tvalue ;
if (mFunctionType == AT_RMS)
y[xy_size++] = value * value ;
else
y[xy_size++] = value ;
toVal = tvalue ;
break;
}
if (first == 0) {
if( meas->m_from != 0.0e0 && (i > 0) ){
// interpolate starting value.
if (!(AlmostEqualUlps( tvalue, meas->m_from, 100))){
value = measure_interpolate( time, d, i-1, i, meas->m_from, 'y' );
tvalue = meas->m_from ;
}
}
meas->m_measured_at = tvalue ;
first = 1;
}
x[xy_size] = tvalue ;
if (mFunctionType == AT_RMS)
y[xy_size++] = value * value ;
else
y[xy_size++] = value ;
}
// evaluate segment width
for ( i = 0; i < xy_size-1; i++ ) width[i] = x[i+1] - x[i] ;
width[i++] = 0;
width[i++] = 0;
// Compute Integral (area under curve)
i = 0;
sum1 = sum2 = sum3 = 0.0 ;
while ( i < xy_size-1 ) {
// Simpson's 3/8 Rule
if ( AlmostEqualUlps( width[i], width[i+1], 100 ) &&
AlmostEqualUlps( width[i], width[i+2], 100 ) ) {
sum1 += 3*width[i] * (y[i] + 3*(y[i+1] + y[i+2]) + y[i+3]) / 8.0;
i += 3;
}
// Simpson's 1/3 Rule
else if ( AlmostEqualUlps( width[i], width[i+1], 100 ) ) {
sum2 += width[i] * (y[i] + 4*y[i+1] + y[i+2]) / 3.0 ;
i += 2;
}
// Trapezoidal Rule
else if ( !AlmostEqualUlps( width[i], width[i+1], 100 ) ) {
sum3 += width[i] * (y[i] + y[i+1]) / 2;
i++;
}
}
/* Now set the measurement values if not set */
if( toVal < 0.0 ){
toVal = time->v_realdata[d->v_length-1];
}
meas->m_from = meas->m_measured_at ;
meas->m_to = toVal ;
if (mFunctionType == AT_RMS) {
meas->m_measured = (sum1 + sum2 + sum3)/ (toVal - meas->m_measured_at) ;
meas->m_measured = sqrt(meas->m_measured);
} else {
meas->m_measured = ( sum1 + sum2 + sum3 );
}
txfree(x); txfree(y); txfree(width);
} /* end measure_rms_integral() */
/* -----------------------------------------------------------------
* Function: Wrapper function to process a RMS measurement.
* ----------------------------------------------------------------- */
static void measure_rms(
MEASUREPTR meas /* in : parsed measurement data request */
) {
// RMS (root mean squared):
// Calculates the square root of the area under the 'out_var2' curve
// divided be the period of interest
measure_rms_integral(meas,AT_RMS) ;
return;
}
void measure_integ( ) {
/* -----------------------------------------------------------------
* Function: Wrapper function to process a integration measurement.
* ----------------------------------------------------------------- */
static void measure_integ(
MEASUREPTR meas /* in : parsed measurement data request */
) {
// INTEGRAL INTEG
measure_rms_integral(meas,AT_INTEG) ;
return;
}
/* still some more work to do.... */
void measure_deriv( ) {
// DERIVATIVE DERIV
return;
@ -356,13 +690,6 @@ void measure_ERR3( ) {
return;
}
void measure_errMessage(char *mName, char *mFunction, char *trigTarg, char *errMsg, bool autocheck) {
if (autocheck) return;
printf("\tmeasure '%s' failed\n", mName);
printf("Error: measure %s %s(%s) :\n", mName, mFunction, trigTarg);
printf("\t%s\n",errMsg);
return;
}
void com_dotmeasure( ) {
@ -373,20 +700,38 @@ void com_dotmeasure( ) {
return;
}
int measure_valid_vector(char *vec) {
/* -----------------------------------------------------------------
* Function: Given a measurement variable name, see if the analysis
* has generated a measure vector for it. Returns TRUE if it exists
* or varname is NULL, Return FALSE otherwise
* ----------------------------------------------------------------- */
static int measure_valid_vector(
char *varname /* in: requested variable name */
) {
struct dvec *d;
struct dvec *d; /* measurement vector */
if(vec == NULL)
return 1;
d = vec_get(vec);
if(varname == NULL)
return TRUE;
d = vec_get(varname);
if (d == NULL)
return 0;
return FALSE;
return 1;
return TRUE;
}
int measure_parse_stdParams (struct measure *meas, wordlist *wl, wordlist *wlBreak, char *errbuf) {
/* -----------------------------------------------------------------
* Function: Given a wordlist and measurement structure, parse the
* standard parameters such as RISE, FALL, VAL, TD, FROM, TO, etc.
* in a measurement statement. We also check the appropriate
* variables found in the measurement statement.
* ----------------------------------------------------------------- */
static int measure_parse_stdParams (
MEASUREPTR meas, /* in : measurement structure */
wordlist *wl, /* in : word list to parse */
wordlist *wlBreak, /* out: where we stopped parsing */
char *errbuf /* in/out: buffer where we write error messages */
) {
int pCnt;
char *p, *pName, *pValue;
@ -475,7 +820,17 @@ int measure_parse_stdParams (struct measure *meas, wordlist *wl, wordlist *wlBre
return 1;
}
int measure_parse_find (struct measure *meas, wordlist *wl, wordlist *wlBreak, char *errbuf) {
/* -----------------------------------------------------------------
* Function: Given a wordlist and measurement structure, parse a
* FIND measurement statement. Most of the work is done by calling
* measure_parse_stdParams.
* ----------------------------------------------------------------- */
static int measure_parse_find (
MEASUREPTR meas, /* in : measurement structure */
wordlist *wl, /* in : word list to parse */
wordlist *wlBreak, /* out: where we stopped parsing */
char *errbuf /* in/out: buffer where we write error messages */
) {
int pCnt;
char *p, *pName, *pVal;
@ -497,9 +852,7 @@ int measure_parse_find (struct measure *meas, wordlist *wl, wordlist *wlBreak, c
p = wl->wl_word;
if (pCnt == 0 ) {
// meas->m_vec =(char *)tmalloc(strlen(wl->wl_word)+1);
// strcpy(meas->m_vec, cp_unquote(wl->wl_word));
meas->m_vec= cp_unquote(wl->wl_word);
meas->m_vec= cp_unquote(wl->wl_word);
} else if (pCnt == 1) {
pName = strtok(p, "=");
@ -537,7 +890,16 @@ int measure_parse_find (struct measure *meas, wordlist *wl, wordlist *wlBreak, c
return 1;
}
int measure_parse_when (struct measure *meas, wordlist *wl, char *errBuf) {
/* -----------------------------------------------------------------
* Function: Given a wordlist and measurement structure, parse a
* WHEN measurement statement. Most of the work is done by calling
* measure_parse_stdParams.
* ----------------------------------------------------------------- */
static int measure_parse_when (
MEASUREPTR meas, /* in : measurement structure */
wordlist *wl, /* in : word list to parse */
char *errBuf /* in/out: buffer where we write error messages */
) {
int pCnt;
char *p, *pVar1, *pVar2;
@ -584,7 +946,18 @@ int measure_parse_when (struct measure *meas, wordlist *wl, char *errBuf) {
}
int measure_parse_trigtarg (struct measure *meas, wordlist *words, wordlist *wlTarg, char *trigTarg, char *errbuf) {
/* -----------------------------------------------------------------
* Function: Given a wordlist and measurement structure, parse a
* TRIGGER or TARGET clause of a measurement statement. Most of the
* work is done by calling measure_parse_stdParams.
* ----------------------------------------------------------------- */
static int measure_parse_trigtarg (
MEASUREPTR meas, /* in : measurement structure */
wordlist *words, /* in : word list to parse */
wordlist *wlTarg, /* out : where we stopped parsing target clause */
char *trigTarg, /* in : type of clause */
char *errbuf /* in/out: buffer where we write error messages */
) {
int pcnt;
char *p;
@ -634,9 +1007,21 @@ int measure_parse_trigtarg (struct measure *meas, wordlist *words, wordlist *wlT
return 1;
}
/* -----------------------------------------------------------------
* Function: Given a wordlist, extract the measurement statement,
* process it, and return a result. If out_line is furnished, we
* format and copy the result it this string buffer. The autocheck
* variable allows us to check for "autostop". This function is
* called from measure.c. We use the functions in this file because
* the parsing is much more complete and thorough.
* ----------------------------------------------------------------- */
int
get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck)
{
get_measure2(
wordlist *wl, /* in: a word list for us to process */
double *result, /* out : the result of the measurement */
char *out_line, /* out: formatted result - may be NULL */
bool autocheck /* in: TRUE if checking for "autostop"; FALSE otherwise */
) {
wordlist *words, *wlTarg, *wlWhen;
char errbuf[100];
char *mType = NULL; // analysis type
@ -673,7 +1058,7 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck)
return MEASUREMENT_FAILURE;
}
precision = get_measure_precision() ;
precision = measure_get_precision() ;
wl_cnt = 0;
while (words) {
@ -687,43 +1072,14 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck)
break;
case 2:
{
mFunction = cp_unquote(words->wl_word);
// Functions
if (strcasecmp(mFunction,"DELAY")==0)
mFunctionType = AT_DELAY;
else if (strcasecmp(mFunction,"TRIG")==0)
mFunctionType = AT_DELAY;
else if (strcasecmp(mFunction,"FIND")==0)
mFunctionType = AT_FIND;
else if (strcasecmp(mFunction,"WHEN")==0)
mFunctionType = AT_WHEN;
else if (strcasecmp(mFunction,"AVG")==0)
mFunctionType = AT_AVG;
else if (strcasecmp(mFunction,"MIN")==0)
mFunctionType = AT_MIN;
else if (strcasecmp(mFunction,"MAX")==0)
mFunctionType = AT_MAX;
else if (strcasecmp(mFunction,"RMS")==0)
mFunctionType = AT_RMS;
else if (strcasecmp(mFunction,"PP")==0)
mFunctionType = AT_PP;
else if (strcasecmp(mFunction,"INTEG")==0)
mFunctionType = AT_INTEG;
else if (strcasecmp(mFunction,"DERIV")==0)
mFunctionType = AT_DERIV;
else if (strcasecmp(mFunction,"ERR")==0)
mFunctionType = AT_ERR;
else if (strcasecmp(mFunction,"ERR1")==0)
mFunctionType = AT_ERR1;
else if (strcasecmp(mFunction,"ERR2") == 0)
mFunctionType = AT_ERR2;
else if (strcasecmp(mFunction,"ERR3") == 0)
mFunctionType = AT_ERR3;
else {
printf("\tmeasure '%s' failed\n", mName);
printf("Error: measure %s :\n", mName);
printf("\tno such function as '%s'\n", mFunction);
return MEASUREMENT_FAILURE;
mFunctionType = measure_function_type(words->wl_word);
if ( mFunctionType == AT_UNKNOWN ){
if(!(autocheck)){
printf("\tmeasure '%s' failed\n", mName);
printf("Error: measure %s :\n", mName);
printf("\tno such function as '%s'\n", words->wl_word);
}
return MEASUREMENT_FAILURE;
}
break;
}
@ -771,7 +1127,7 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck)
case AT_TRIG:
{
// trig parameters
measure *measTrig, *measTarg;
MEASUREPTR measTrig, measTarg;
measTrig = (struct measure*)tmalloc(sizeof(struct measure));
measTarg = (struct measure*)tmalloc(sizeof(struct measure));
@ -836,7 +1192,7 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck)
}
case AT_FIND:
{
measure *meas, *measFind;
MEASUREPTR meas, measFind;
meas = (struct measure*)tmalloc(sizeof(struct measure));
measFind = (struct measure*)tmalloc(sizeof(struct measure));
@ -891,7 +1247,7 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck)
}
case AT_WHEN:
{
measure *meas;
MEASUREPTR meas;
meas = (struct measure*)tmalloc(sizeof(struct measure));
if (measure_parse_when(meas, words, errbuf) ==0) {
@ -918,14 +1274,43 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck)
return MEASUREMENT_OK;
}
case AT_RMS:
printf("\tmeasure '%s' failed\n", mName);
printf("Error: measure %s :\n", mName);
printf("\tfunction '%s' currently not supported\n", mFunction);
break;
case AT_INTEG:
{
// trig parameters
MEASUREPTR meas;
meas = (struct measure*)tmalloc(sizeof(struct measure));
if (measure_parse_trigtarg(meas, words , NULL, "trig", errbuf)==0) {
measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck);
return MEASUREMENT_FAILURE;
}
// measure
measure_rms_integral(meas,mFunctionType);
if (meas->m_measured == 0.0e0) {
sprintf(errbuf,"out of interval\n");
measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck); // ??
return MEASUREMENT_FAILURE;
}
if (meas->m_at == -1)
meas->m_at = 0.0e0;
// print results
if( out_line ){
sprintf(out_line,"%-20s= %.*e from= %.*e to= %.*e\n", mName, precision, meas->m_measured, precision, meas->m_from, precision, meas->m_to);
} else {
printf("%-20s= %.*e from= %.*e to= %.*e\n", mName, precision, meas->m_measured, precision, meas->m_from, precision, meas->m_to);
}
*result=meas->m_measured;
return MEASUREMENT_OK;
}
case AT_AVG:
{
// trig parameters
measure *meas;
MEASUREPTR meas;
meas = (struct measure*)tmalloc(sizeof(struct measure));
if (measure_parse_trigtarg(meas, words , NULL, "trig", errbuf)==0) {
@ -959,7 +1344,7 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck)
case AT_MAX:
{
// trig parameters
measure *measTrig;
MEASUREPTR measTrig;
measTrig = (struct measure*)tmalloc(sizeof(struct measure));
if (measure_parse_trigtarg(measTrig, words , NULL, "trig", errbuf)==0) {
@ -993,7 +1378,7 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck)
{
double minValue, maxValue;
measure *measTrig;
MEASUREPTR measTrig;
measTrig = (struct measure*)tmalloc(sizeof(struct measure));
if (measure_parse_trigtarg(measTrig, words , NULL, "trig", errbuf)==0) {
@ -1028,7 +1413,6 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck)
*result = (maxValue - minValue);
return MEASUREMENT_OK;
}
case AT_INTEG:
case AT_DERIV:
case AT_ERR:
case AT_ERR1:

7
src/frontend/com_measure2.h

@ -3,8 +3,9 @@
#include <config.h>
int get_measure_precision(void) ;
/* void com_measure2(wordlist *wl); */
int get_measure2(wordlist *wl,double *result,char *out_line, bool auto_check) ;
extern int get_measure_precision(void) ;
/* void com_measure2(wordlist *wl); */
extern int get_measure2(wordlist *wl,double *result,char *out_line, bool auto_check) ;
extern int measure_extract_variables( char *line ) ;
#endif

36
src/frontend/dotcards.c

@ -23,13 +23,13 @@ $Id$
#include "variable.h"
#include "fourier.h"
#include "breakp2.h"
#include "com_measure2.h"
/* Extract all the .save lines */
static void fixdotplot(wordlist *wl);
static void fixdotprint(wordlist *wl);
static char * fixem(char *string);
static wordlist * gettoks(char *s);
static struct plot *
@ -90,6 +90,7 @@ ft_savedotargs(void)
static wordlist all = { "all", NULL };
int isaplot;
int i;
int status;
if (!ft_curckt) /* Shouldn't happen. */
return 0;
@ -137,15 +138,10 @@ ft_savedotargs(void)
com_save2(w, "TRAN"); /* A hack */
}
} else if (ciprefix(".measure", s)) {
(void) gettok(&s);
name = gettok(&s);
(void) gettok(&s);
(void) gettok(&s);
if (!(w = gettoks(s))) {
fprintf(cp_err, "Warning: no nodes given: %s\n", iline->wl_word);
}
some = 1;
com_save2(w, name);
status = measure_extract_variables( s ) ;
if(!(status)){
some = 1;
}
} else if (ciprefix(".op", s)) {
some = 1;
com_save2(&all, "OP");
@ -157,6 +153,24 @@ ft_savedotargs(void)
return some;
}
void
ft_savemeasure(void)
{
char *s;
wordlist *iline;
if (!ft_curckt) /* Shouldn't happen. */
return ;
for (iline = ft_curckt->ci_commands; iline; iline = iline->wl_next) {
s = iline->wl_word;
if (ciprefix(".measure", s)) {
(void) measure_extract_variables( s ) ;
}
}
return ;
}
/* Execute the .whatever lines found in the deck, after we are done running.
* We'll be cheap and use cp_lexer to get the words... This should make us
* spice-2 compatible. If terse is TRUE then there was a rawfile, so don't
@ -506,7 +520,7 @@ fixem(char *string)
}
static wordlist *
wordlist *
gettoks(char *s)
{
char *t;

1
src/frontend/dotcards.h

@ -9,6 +9,7 @@
void ft_dotsaves(void);
int ft_savedotargs(void);
int ft_cktcoms(bool terse);
wordlist *gettoks(char *s);
#endif

592
src/frontend/measure.c

@ -22,11 +22,7 @@
void winmessage(char* new_msg);
#endif
#define OLD_WAY /* do not use functions from com_measure2.c */
#ifndef OLD_WAY
static wordlist *measure_parse_line( char *line ) ;
#endif
static bool measure_valid[20000];/* TRUE: if measurement no. [xxx] has been done successfully
(not used anywhere)*/
@ -34,257 +30,7 @@ static bool just_chk_meas; /* TRUE: only check if measurement can be done succ
no output generated (if option autostop is set)*/
static bool measures_passed; /* TRUE: stop simulation (if option autostop is set)*/
/* returns interpolated time point (char x_or_y='x') or interpolated data value */
static double
interpolate(
struct dvec *time, /*in: vector of time points */
struct dvec *values, /*in: vector of corresponding data points */
int i, /*in: index to first time/data couple */
int j, /*in: index to second time/data couple, i nad j setting the interval */
double var_value, /*in: either time or data value */
char x_or_y /*in: set to 'x': requires var_value to be data point, returns time;
otherwise expects var_value to be time, returns data value */
) {
double slope = (values->v_realdata[j] - values->v_realdata[i])/(time->v_realdata[j] - time->v_realdata[i]);
double yint = values->v_realdata[i] - slope*time->v_realdata[i];
double result;
if ( x_or_y == 'x' ) result = (var_value - yint)/slope;
else result = slope*var_value + yint;
return result;
}
/* Takes a data value and returns corresponding time, but only after the number of
data crossings given by e.g. 'rise=3' have passed. */
static double
get_volt_time(
struct dvec *time, /*in: vector of time points */
struct dvec *values, /*in: vector of corresponding data points */
double value, /*in: data value, for which time is sought */
char polarity, /*in: 'r' (rise) or 'f' (fall) */
int mindex, /*in: no. of times the data sequence has to cross 'value', before measurement commences */
bool *failed /*out: TRUE if syntax error or time point not found */
) {
int i = 0, count = 0;
double comp_time = 0;
for ( i = 0; i < values->v_length-1; i++ ) {
if ( polarity == 'r' ) {
if ( values->v_realdata[i] < value && value <= values->v_realdata[i+1] ) {
/* increase 'count' if rising slope data cross 'value' */
count++;
/* return interpolated time value only after the data sequence has crossed
'value' mindex times*/
if ( count == mindex ) comp_time = interpolate( time, values, i, i+1, value, 'x' );
}
}
else if ( polarity == 'f' ) {
if ( values->v_realdata[i] >= value && value > values->v_realdata[i+1] ) {
/* increase 'count' if falling slope data cross 'value' */
count++;
/* return interpolated time value only after the data sequence has crossed
'value' mindex times*/
if ( count == mindex ) comp_time = interpolate( time, values, i, i+1, value, 'x' );
}
}
else {
if ( just_chk_meas != TRUE ) fprintf( stderr, "Error: unknown signal polarity '%c'; valid types are 'r' or 'f'.\n", polarity );
*failed = TRUE;
}
}
if ( AlmostEqualUlps( comp_time, 0, 100 ) ) *failed = TRUE;
return comp_time;
}
/* Evaluate the delay between time values at trig and targ i or v levels.
Called by fcn do_delay_measurement().
Returns FALSE if successful.*/
static bool
measure(
char *trig_name, /*in: name (e.g. in) of vector (e.g. v(in)) following trig parameter */
double trig_value, /*in: i or v value following trig parameter */
char trig_polarity, /*in: r for rising slope, f for falling slope */
int trig_index, /*in: time is measured only after this number of rising (
falling) slopes with trigvalue has been detected*/
char *targ_name, /*in: name (e.g. in) of vector (e.g. v(in)) following targ parameter */
double targ_value, /*in: i or v level following targ parameter */
char targ_polarity, /*in: r for rising slope, f for falling slope */
int targ_index, /*in: time is measured only after this number of rising (
falling) slopes with targvalue has been detected */
double *result, /*out: difference between *targ_time and *trig_time*/
double *trig_time, /*out: time at given i or v level following trig parameter*/
double *targ_time /*out: time at given i or v level following targ parameter*/
) {
struct dvec *time = vec_get("time");
struct dvec *trig = vec_get(trig_name);
struct dvec *targ = vec_get(targ_name);
bool failed = FALSE;
if ( !time ) { if ( just_chk_meas != TRUE ) fprintf( stderr, "Error: problem accessing vector 'time'!\n" ); return TRUE; }
if ( !trig ) { if ( just_chk_meas != TRUE ) fprintf( stderr, "Error: problem accessing vector '%s'!\n", trig_name ); return TRUE; }
if ( !targ ) { if ( just_chk_meas != TRUE ) fprintf( stderr, "Error: problem accessing vector '%s'!\n", targ_name ); return TRUE; }
*trig_time = get_volt_time( time, trig, trig_value, trig_polarity, trig_index, &failed );
*targ_time = get_volt_time( time, targ, targ_value, targ_polarity, targ_index, &failed );
*result = *targ_time - *trig_time;
return failed;
}
/*Do any other measurements:
avg: (average) calculates the area under the out_var divided by the periods of interest
rms: (root mean squared) calculates the square root of the area under the out_var^2 curve
divided by the period of interest
integ(ral): calculate the integral in period of interest
min|max: find min or max value in period of interest
when: get time when an vetor reaches a value.
Called by fcn do_other_measurement().
Returns FALSE if successful.
*/
static bool
measure2(
char *meas_type, /* one of avg|rms|integ(ral)|min|max|when*/
char *vec_name, /*in: name (e.g. 'v0') of vector (e.g. i(v0) )*/
char vec_type, /*in: type (e.g. 'i') of vector (e.g. i(v0) ), may be 'v' or 'i'*/
double from, /*in: start value (e.g. of time) defining region of interest */
double to, /*in: stop value */
double *result, /*out: measurement result */
double *result_time /*out: time value where *result occurs (not valid for avg, rms, integ) */
) {
struct dvec *time = vec_get("time");
struct dvec *vec;
int xy_size = 0;
double *x, *y, *width, sum1 = 0, sum2 = 0, sum3 = 0;
double init_val;
char tmp_vec_name[1000];
double prev_result = 0;
bool failed = FALSE, first_time = TRUE, constant_y = TRUE;
int i, idx, upflag ;
if ( to < from ) { if ( just_chk_meas != TRUE ) fprintf( stderr, "Error: (measure2) 'to' time (%e) < 'from' time (%e).\n", to, from ); return TRUE; }
if ( vec_type == 'i' ) {
if ( strstr( vec_name, ".v" ) ) sprintf( tmp_vec_name, "v.%s#branch", vec_name );
else sprintf( tmp_vec_name, "%s#branch", vec_name );
}
else sprintf( tmp_vec_name, "%s", vec_name );
vec = vec_get( tmp_vec_name );
if ( !time ) { if ( just_chk_meas != TRUE ) fprintf( stderr, "Error: problem accessing vector 'time'!\n" ); return TRUE; }
if ( !vec ) { if ( just_chk_meas != TRUE ) fprintf( stderr, "Error: problem accessing vector '%s'!\n", tmp_vec_name ); return TRUE; }
if ( strcmp( meas_type, "max" ) == 0 || strcmp( meas_type, "min" ) == 0 ) {
for ( i = 0; i < vec->v_length; i++ ) {
if ( time->v_realdata[i] >= from && ( i+1 < time->v_length && time->v_realdata[i+1] <= to ) ) {
prev_result = *result;
if ( first_time ) {
first_time = FALSE;
*result = vec->v_realdata[i];
*result_time = time->v_realdata[i];
} else {
*result = ( strcmp( meas_type, "max" ) == 0 ) ? MAX( *result, vec->v_realdata[i] ) : MIN( *result, vec->v_realdata[i] );
if ( !AlmostEqualUlps( prev_result, *result, 100 ) ) *result_time = time->v_realdata[i];
}
}
}
}
else if ( strcmp( meas_type, "avg" ) == 0 || strcmp( meas_type, "rms" ) == 0 ||
strcmp( meas_type, "integral" ) == 0 || strcmp( meas_type, "integ" ) == 0 ) {
x = (double *) tmalloc(time->v_length * sizeof(double));
y = (double *) tmalloc(time->v_length * sizeof(double));
width = (double *) tmalloc(time->v_length * sizeof(double));
// create new set of values over interval [from, to] -- interpolate if necessary
for ( i = 0; i < vec->v_length; i++ ) {
if ( time->v_realdata[i] >= from && time->v_realdata[i] <= to ) {
*(x+xy_size) = time->v_realdata[i];
*(y+xy_size++) = ( strcmp( meas_type, "avg" ) == 0 || ciprefix( "integ", meas_type ) ) ? vec->v_realdata[i] : pow(vec->v_realdata[i],2);
}
}
// evaluate segment width
for ( i = 0; i < xy_size-1; i++ ) *(width+i) = *(x+i+1) - *(x+i);
*(width+i++) = 0;
*(width+i++) = 0;
// see if y-value constant
for ( i = 0; i < xy_size-1; i++ )
if ( !AlmostEqualUlps( *(y+i), *(y+i+1), 100 ) ) constant_y = FALSE;
// Compute Integral (area under curve)
i = 0;
while ( i < xy_size-1 ) {
// Simpson's 3/8 Rule
if ( AlmostEqualUlps( *(width+i), *(width+i+1), 100 ) && AlmostEqualUlps( *(width+i), *(width+i+2), 100 ) ) {
sum1 += 3*(*(width+i))*(*(y+i) + 3*(*(y+i+1) + *(y+i+2)) + *(y+i+3))/8;
i += 3;
}
// Simpson's 1/3 Rule
else if ( AlmostEqualUlps( *(width+i), *(width+i+1), 100 ) ) {
sum2 += *(width+i)*(*(y+i) + 4*(*(y+i+1)) + *(y+i+2))/3;
i += 2;
}
// Trapezoidal Rule
else if ( !AlmostEqualUlps( *(width+i), *(width+i+1), 100 ) ) {
sum3 += *(width+i)*(*(y+i) + *(y+i+1))/2;
i++;
}
}
if ( !ciprefix( "integ", meas_type ) ) {
*result = (sum1 + sum2 + sum3)/(to - from);
if ( strcmp( meas_type, "rms" ) == 0 ) *result = sqrt(*result);
if ( strcmp( meas_type, "avg" ) == 0 && constant_y == TRUE ) *result = *y;
}
else {
*result = ( sum1 + sum2 + sum3 );
}
txfree(x); txfree(y); txfree(width);
}
else if ( strcmp( meas_type, "when" ) == 0 ){
init_val = vec->v_realdata[0] ;
/* 'from' is used as input value */
if ( AlmostEqualUlps( init_val, from, 100 ) ){
/* match right out of the gate. */
*result = vec->v_realdata[0];
*result_time = time->v_realdata[0];
return failed ;
}
if( init_val < from ){
/* search upward */
upflag = TRUE ;
} else {
/* search downward */
upflag = FALSE ;
}
idx = -1 ;
for ( i = 0; i < vec->v_length; i++ ) {
if ( AlmostEqualUlps( vec->v_realdata[i], from, 100 ) ){
idx = i ;
break ;
} else if( upflag && (vec->v_realdata[i] > from) ){
idx = i ;
break ;
} else if( !(upflag) && (vec->v_realdata[i] < from) ){
idx = i ;
break ;
}
}
if( idx < 0 ){
return failed;
}
*result = vec->v_realdata[idx] ;
*result_time = interpolate( time, vec, idx-1, i, from, 'x' );
}
else {
if ( just_chk_meas != TRUE ) fprintf( cp_err, "Error: (measure2) unknown meas function '%s'.\n", meas_type );
return TRUE;
}
return failed;
}
static bool
chkAnalysisType( char *an_type ) {
@ -299,49 +45,13 @@ chkAnalysisType( char *an_type ) {
else return TRUE;
}
/* Gets pointer to integer value after 'xxx=' and advances pointer of *line.
On error returns FALSE. */
static bool
get_int_value(
char **line, /*in|out: pointer to line to be parsed */
char *name, /*in: xxx e.g. 'fall' from example 'fall=2' */
int *value /*out: return value (e.g. 2 from 'fall=2' */
) {
/*get token (e.g. 'fall=1' and advance pointer*/
char *token = gettok(line);
bool return_val = TRUE;
char *equal_ptr;
if ( strncmp( token, name, strlen(name) ) != 0 ) {
if ( just_chk_meas != TRUE ) fprintf( cp_err, "Error: syntax error for measure statement; expecting next field to be '%s'.\n", name );
return_val = FALSE;
} else {
/* see if '=' is last char of current token -- implies we need to read value in next token */
if ( *(token + strlen(token) - 1) == '=' ) {
txfree(token);
token = gettok(line);
*value = atoi(token);
} else {
if ( (equal_ptr = strstr( token, "=" )) ) {
*value = atoi(equal_ptr+1);
} else {
if ( just_chk_meas != TRUE ) fprintf( cp_err, "Error: syntax error for measure statement; missing '='!\n" );
return_val = FALSE;
}
}
}
txfree(token);
return return_val;
}
/* Gets pointer to double value after 'xxx=' and advances pointer of *line.
On error returns FALSE. */
static bool
get_double_value(
char **line, /*in|out: pointer to line to be parsed */
char *name, /*in: xxx e.g. 'val' from 'val=0.5' */
char **line, /*in|out: pointer to line to be parsed */
char *name, /*in: xxx e.g. 'val' from 'val=0.5' */
double *value /*out: return value (e.g. 0.5) from 'val=0.5'*/
) {
char *token = gettok(line);
@ -375,235 +85,6 @@ get_double_value(
return return_val;
}
/*-------------------------------------------------------------------------*
gettok_paren skips over whitespace and returns the next token found. Here it
is used only to return part of a vector, eg V(in) or I(mynode).
For example v(in) has already been stripped to in) when gettok_paren is called.
gettok_paren returns 'in', leaving ')' as the next character of s.
Only called from fcn get_vector_name().
*-------------------------------------------------------------------------*/
static char *
gettok_paren(char **s)
{
char buf[BSIZE_SP];
int i = 0;
char c;
int paren;
paren = 0;
/* skip over leading white spaces */
while (isspace(**s))
(*s)++;
/* if nothing left (end of line), return NULL */
if (!**s)
return (NULL);
while ((c = **s) && !isspace(c)) {
if (c == '('/*)*/)
paren += 1;
else if (c == /*(*/')'){
paren -= 1;
if( paren <= 0 ) /* added over gettok */
break ;
} else if (c == ',' && paren < 1)
break;
buf[i++] = *(*s)++;
}
buf[i] = '\0';
/* skip over trailing white spaces and commas*/
while (isspace(**s) || **s == ',')
(*s)++;
return (copy(buf));
}
static char*
get_vector_name( char **line ) {
char *token, *name;
// token = name = gettok(line);
token = name = gettok_paren(line);
// *(name + strlen(name) - 1) = '\0';
name = strdup(name); txfree(token);
return name;
}
/* Evaluate measurement types trig|delay .
Called by do_measure().
Calls measure(). */
static bool
do_delay_measurement(
char *resname, /*in: name of result parameter, defined by user*/
char *out_line, /*out: output for printing */
char *line, /*in: .meas card, first four parameters stripped */
char *o_line, /*in: .meas card, complete */
int meas_index, /*in: number of actual measurement */
double *result /*out: delay value returned by measure() */
/*global variable measures_passed
out: set to FALSE if measurement failed (used with autostop)*/
) {
char *trig_name, *targ_name, *token;
char trig_type, targ_type, trig_polarity, targ_polarity;
double targ_value, trig_value;
int trig_index, targ_index;
double trig_time = 0, targ_time = 0;
int precision = get_measure_precision();
bool failed;
measure_valid[meas_index] = FALSE;
trig_type = *line; line += 2; /* skip over vector type and open paren */
trig_name = get_vector_name( &line );
while(*line && !(*line == ')')) line++; /* find ')' */
line++; /* move on beyond ')' */
if ( trig_type != 'v' && trig_type != 'i' ) {
if ( just_chk_meas != TRUE ) {
fprintf( cp_err, "Error: unexpected vector type '%c' for .meas!\n", trig_type );
fprintf( cp_err, " %s\n", o_line );
}
txfree(trig_name); return FALSE;
}
if ( !get_double_value( &line, "val", &trig_value ) ) { if ( just_chk_meas != TRUE ) fprintf( cp_err, " %s\n", o_line ); txfree(trig_name); return FALSE; }
if ( strncmp( line, "rise", 4 ) == 0 ) {
trig_polarity = 'r';
if ( !get_int_value( &line, "rise", &trig_index ) ) { if ( just_chk_meas != TRUE ) fprintf( cp_err, " %s\n", o_line ); txfree(trig_name); return FALSE; }
}
else if ( strncmp( line, "fall", 4 ) == 0 ) {
trig_polarity = 'f';
if ( !get_int_value( &line, "fall", &trig_index ) ) { if ( just_chk_meas != TRUE ) fprintf( cp_err, " %s\n", o_line ); txfree(trig_name); return FALSE; }
}
else {
if ( just_chk_meas != TRUE ) {
fprintf( cp_err, "Error: expecting next token to be rise|fall for measurement!\n" );
fprintf( cp_err, " %s\n", o_line );
}
txfree(trig_name); return FALSE;
}
token = gettok(&line);
if ( strcmp(token, "targ" ) != 0 ) {
if ( just_chk_meas != TRUE ) {
fprintf( cp_err, "Error: expected 'targ' as next token in .meas statement!\n" );
fprintf( cp_err, " %s\n", o_line );
}
txfree(token); txfree(trig_name); return FALSE;
}
txfree(token);
targ_type = *line; line += 2; /* skip over vector type and open paren */
targ_name = get_vector_name( &line );
while(*line && !(*line == ')')) line++; /* find ')' */
line++; /* move on beyond ')' */
if ( targ_type != 'v' && targ_type != 'i' ) {
if ( just_chk_meas != TRUE ) {
fprintf( cp_err, "Error: unexpected vector type '%c' for .meas!\n", targ_type );
fprintf( cp_err, " %s\n", o_line );
}
txfree(trig_name); txfree(targ_name); return FALSE;
}
if ( !get_double_value( &line, "val", &targ_value ) ) { if ( just_chk_meas != TRUE ) fprintf( cp_err, " %s\n", o_line ); txfree(trig_name); txfree(targ_name); return FALSE; }
if ( strncmp( line, "rise", 4 ) == 0 ) {
targ_polarity = 'r';
if ( !get_int_value( &line, "rise", &targ_index ) ) { if ( just_chk_meas != TRUE ) fprintf( cp_err, " %s\n", o_line ); txfree(trig_name); txfree(targ_name); return FALSE; }
}
else if ( strncmp( line, "fall", 4 ) == 0 ) {
targ_polarity = 'f';
if ( !get_int_value( &line, "fall", &targ_index ) ) { if ( just_chk_meas != TRUE ) fprintf( cp_err, " %s\n", o_line ); txfree(trig_name); txfree(targ_name); return FALSE; }
}
else {
if ( just_chk_meas != TRUE ) {
fprintf( cp_err, "Error: expecting next token to be rise|fall for measurement!\n" );
fprintf( cp_err, " %s\n", o_line );
}
txfree(trig_name); txfree(targ_name); return FALSE;
}
failed = measure( trig_name, trig_value, trig_polarity, trig_index, targ_name, targ_value, targ_polarity,
targ_index, result, &trig_time, &targ_time );
if ( !failed ) {
sprintf( out_line, "%-15s= %.*e targ= %.*e trig= %.*e\n", resname, precision, *result, precision, targ_time, precision, trig_time );
measure_valid[meas_index] = TRUE;
} else {
measures_passed = FALSE;
sprintf( out_line, "%-15s= failed\n", resname );
measure_valid[meas_index] = FALSE;
}
txfree(trig_name); txfree(targ_name);
return ( failed ) ? FALSE : TRUE;
}
static bool
do_other_measurement( char *resname, char *out_line, char *meas_type, char *line, char *o_line, int meas_index, double *result ) {
char *vec_name;
char vec_type;
double from, to, result_time = 0;
int precision = get_measure_precision();
bool failed;
vec_type = *line; line += 2; /* skip over vector type and open paren */
vec_name = get_vector_name( &line );
while(*line && !(*line == ')')) line++; /* find ')' */
line++; /* move on beyond ')' */
if ( vec_type != 'v' && vec_type != 'i' ) {
if ( just_chk_meas != TRUE ) {
fprintf( cp_err, "Error: unexpected vector type '%c' for .meas!\n", vec_type );
fprintf( cp_err, " %s\n", o_line );
}
txfree(vec_name);
return FALSE;
}
if ( strcmp( meas_type, "when" ) == 0 ){
if ( !get_double_value( &line, NULL, &from ) ) {
if ( just_chk_meas != TRUE ) fprintf( cp_err, " %s\n", o_line );
txfree(vec_name);
return FALSE;
}
to = from ;
} else {
if ( !get_double_value( &line, "from", &from ) ) {
if ( just_chk_meas != TRUE ) fprintf( cp_err, " %s\n", o_line );
txfree(vec_name);
return FALSE;
}
if ( !get_double_value( &line, "to", &to ) ) {
if ( just_chk_meas != TRUE ) fprintf( cp_err, " %s\n", o_line );
txfree(vec_name);
return FALSE;
}
}
failed = measure2( meas_type, vec_name, vec_type, from, to, result, &result_time );
if ( !failed ) {
if ( strcmp( meas_type, "max" ) == 0 || strcmp( meas_type, "min" ) == 0 )
sprintf( out_line, "%-15s= %.*e at= %.*e\n", resname, precision, *result, precision, result_time );
else if ( strcmp( meas_type, "when" ) == 0 )
sprintf( out_line, "%-15s= %.*e\n", resname, precision, result_time ) ;
else
sprintf( out_line, "%-15s= %.*e from= %.*e to= %.*e\n", resname, precision, *result, precision, from, precision, to );
measure_valid[meas_index] = TRUE;
} else {
measures_passed = FALSE;
sprintf( out_line, "%-15s= failed\n", resname );
measure_valid[meas_index] = FALSE;
}
txfree(vec_name);
return ( failed ) ? FALSE : TRUE;
}
/* Entry point for .meas evaluation.
Called in fcn dosim() from runcoms.c:335, after simulation is finished
@ -624,7 +105,7 @@ do_measure(
double result = 0;
bool first_time = TRUE;
wordlist *measure_word_list ;
int precision = get_measure_precision();
int precision = measure_get_precision() ;
just_chk_meas = chk_only;
@ -642,9 +123,8 @@ do_measure(
measurement type trig|delay|param|expr|avg|mean|max|min|rms|integ(ral)|when
The measurement type determines how to continue the .meas card.
trig|delay are handled in fcn do_delay_measurement(), param|expr are skipped
in first pass through .meas cards and are treated in second pass,
all others are treated in fcn do_other_measurement().
param|expr are skipped in first pass through .meas cards and are treated in second pass,
all others are treated in fcn get_measure2() (com_measure2.c).
*/
/* first pass through .meas cards: evaluate everything except param|expr */
@ -683,42 +163,27 @@ do_measure(
continue;
}
#ifdef OLD_WAY
if ( strcmp( meastype, "trig" ) == 0 || strcmp( meastype, "delay" ) == 0 ) {
if ( do_delay_measurement( resname, out_line, line, meas_card->li_line, idx++, &result ) && just_chk_meas != TRUE ) {
nupa_add_param( resname, result );
}
}
else if ( strcmp( meastype, "avg" ) == 0 || strcmp( meastype, "mean" ) == 0 ||
strcmp( meastype, "max" ) == 0 || strcmp( meastype, "min" ) == 0 ||
strcmp( meastype, "rms" ) == 0 || strcmp( meastype, "integ" ) == 0 ||
strcmp( meastype, "integral" ) == 0 || strcmp( meastype, "when" ) == 0 ) {
if ( do_other_measurement( resname, out_line, meastype, line, meas_card->li_line, idx++, &result ) && just_chk_meas != TRUE ) {
nupa_add_param( resname, result );
/* New way of processing measure statements using common code
in fcn get_measure2() (com_measure2.c)*/
out_line[0] = EOS ;
measure_word_list = measure_parse_line( meas_card->li_line) ;
if( measure_word_list ){
fail = get_measure2(measure_word_list,&result,out_line,chk_only) ;
if( fail ){
measure_valid[idx++] = FALSE;
measures_passed = FALSE;
} else {
if(!(just_chk_meas)){
nupa_add_param( resname, result );
}
measure_valid[idx++] = TRUE;
}
}
else {
wl_free( measure_word_list ) ;
} else {
measure_valid[idx++] = FALSE;
measures_passed = FALSE;
sprintf( out_line, "%-15s= failed\n", resname );
if ( just_chk_meas != TRUE ) {
fprintf( cp_err, "Error: unsupported measurement type '%s' on line %d:\n", meastype, meas_card->li_linenum );
fprintf( cp_err, " %s\n", meas_card->li_line );
}
}
#else /* NEW_WAY */
out_line[0] = EOS ;
measure_word_list = measure_parse_line( meas_card->li_line) ;
fail = get_measure2(measure_word_list,&result,out_line,chk_only) ;
if( fail ){
measure_valid[idx++] = FALSE;
measures_passed = FALSE;
} else {
nupa_add_param( resname, result );
measure_valid[idx++] = TRUE;
}
#endif /* OLD_WAY */
newcard = alloc(struct line);
newcard->li_line = strdup(out_line);
newcard->li_next = NULL;
@ -731,7 +196,7 @@ do_measure(
txfree(an_type); txfree(resname); txfree(meastype);
// see if number of measurements exceeds fixed array size of 20,000
/* see if number of measurements exceeds fixed array size of 20,000 */
if ( idx >= 20000 ) {
fprintf( stderr, "ERROR: number of measurements exceeds 20,000!\nAborting...\n" );
#ifdef HAS_WINDOWS
@ -739,8 +204,10 @@ do_measure(
#endif
exit(-1);
}
} /* end of for loop (first pass through .meas lines) */
/* second pass through .meas cards: now do param|expr .meas statements */
newcard = meas_results;
for ( meas_card = ft_curckt->ci_meas; meas_card != NULL; meas_card = meas_card->li_next ) {
@ -777,7 +244,7 @@ do_measure(
continue;
}
if ( just_chk_meas != TRUE ) fprintf( stdout, "%-15s=", resname );
if ( just_chk_meas != TRUE ) fprintf( stdout, "%-20s=", resname );
if ( just_chk_meas != TRUE ) {
ok = nupa_eval( meas_card->li_line, meas_card->li_linenum );
@ -788,7 +255,7 @@ do_measure(
if ( just_chk_meas != TRUE ) fprintf( stdout, " failed\n" );
}
else {
if ( just_chk_meas != TRUE ) fprintf( stdout, " %.*e\n", precision, result );
if ( just_chk_meas != TRUE ) fprintf( stdout, " %.*e\n", precision, result );
nupa_add_param( resname, result );
}
}
@ -830,7 +297,8 @@ check_autostop( char* what ) {
return flag;
}
static wordlist *measure_parse_line( char *line )
/* parses the .meas line into a wordlist (without leading .meas) */
static wordlist *measure_parse_line( char *line )
{
int len ; /* length of string */
wordlist *wl ; /* build a word list - head of list */

1
src/frontend/numparam/numparam.h

@ -68,6 +68,7 @@ typedef struct _ttdico {
char **dynrefptr;
// char category[Maxline]; /* category of each line */
char *dyncategory;
int hspice_compatibility; /* allow hspice keywords */
} tdico;
void initdico(tdico * dico);

19
src/frontend/numparam/xpressn.c

@ -9,10 +9,7 @@
#include "general.h"
#include "numparam.h"
#include "ngspice.h"
#ifdef _MSC_VER
#define strcasecmp _stricmp
#endif
#include "../compatmode.h"
/* random numbers in /maths/misc/randnumb.c */
extern double gauss();
@ -158,6 +155,8 @@ void
initdico (tdico * dico)
{
int i;
COMPATMODE_T compat_mode;
dico->nbd = 0;
sini(dico->option,sizeof(dico->option)-4);
sini(dico->srcfile,sizeof(dico->srcfile)-4);
@ -172,6 +171,12 @@ initdico (tdico * dico)
dico->tos = 0;
dico->stack[dico->tos] = 0; /* global data beneath */
initkeys ();
compat_mode = ngpsice_compat_mode() ;
if( compat_mode == COMPATMODE_HSPICE )
dico->hspice_compatibility = 1 ;
else
dico->hspice_compatibility = 0 ;
}
/* local semantics for parameters inside a subckt */
@ -1437,7 +1442,11 @@ scanline (tdico * dico, char *s, char *r, unsigned char err)
else
{
pscopy (t, s, i + 1, k - i - 1);
err = evaluate (dico, q, t, 0);
if( dico->hspice_compatibility && (strcasecmp(t,"LAST")==0) ) {
strcpy(q,"last") ;
err=0;
} else
err = evaluate (dico, q, t, 0);
}
i = k;
if (!err)

1
src/include/bool.h

@ -2,6 +2,7 @@
#define _BOOL_H
typedef unsigned char bool;
typedef int BOOL ;
#define BOOLEAN int
#define TRUE 1

12
src/include/macros.h

@ -71,9 +71,17 @@
#ifdef DEBUG
#define DEBUGMSG(textargs) printf(textargs)
#else
#define DS(name_xz) { name_xz }
#define DBGDEFINE(func_xz) func_xz
#else /* ! DEBUG */
#define DEBUGMSG(testargs)
#endif
#define DS(name_xz)
#define DBGDEFINE(func_xz)
#endif /* DEBUG */
/* A few useful macros - string eq just makes the code easier to read */
#define STRINGEQ 0
#define FUNC_NAME(x_xz) char *routine = x_xz
/* Macro that queries the system to find the process time. */

4
src/misc/Makefile.am

@ -11,8 +11,12 @@ libmisc_la_SOURCES = \
alloc.h \
dup2.c \
dup2.h \
hash.h \
hash.c \
ivars.c \
ivars.h \
mempool.c \
mempool.h \
mktemp.c \
mktemp.h \
printnum.c \

5
src/tclspice.c

@ -95,6 +95,7 @@ typedef pthread_t threadId_t;
#include <spicelib/analysis/analysis.h>
#include <misc/ivars.h>
#include <frontend/resource.h>
#include <frontend/com_measure2.h>
#ifndef _MSC_VER /* avoid second definition of VT_BOOL */
#include <frontend/variable.h>
#else
@ -2115,7 +2116,7 @@ static int listTriggers TCL_CMDPROCARGS(clientData,interp,argc,argv){
static int tmeasure TCL_CMDPROCARGS(clientData,interp,argc,argv){
wordlist *wl= NULL;
float mvalue;
double mvalue;
if (argc <= 2) {
Tcl_SetResult(interp, "Wrong # args. spice::listTriggers",TCL_STATIC);
@ -2124,7 +2125,7 @@ static int tmeasure TCL_CMDPROCARGS(clientData,interp,argc,argv){
wl =wl_build((char **)argv);
mvalue = get_measure2(wl);
get_measure2(wl,&mvalue,NULL,FALSE);
printf(" %e \n", mvalue);

4
visualc/vngspice.sln

@ -11,8 +11,8 @@ Global
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Debug|Win32.ActiveCfg = Debug|Win32
{83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Debug|Win32.Build.0 = Debug|Win32
{83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Release|Win32.ActiveCfg = Release|Win32
{83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Release|Win32.Build.0 = Release|Win32
{83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Release|Win32.ActiveCfg = Debug|Win32
{83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Release|Win32.Build.0 = Debug|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

30
visualc/vngspice.vcproj

@ -819,6 +819,10 @@
RelativePath="..\src\frontend\commands.h"
>
</File>
<File
RelativePath="..\src\frontend\compatmode.h"
>
</File>
<File
RelativePath="..\src\frontend\parser\complete.h"
>
@ -1103,12 +1107,16 @@
RelativePath="..\src\frontend\plotting\graphdb.h"
>
</File>
<File
RelativePath="..\src\frontend\plotting\grid.h"
>
</File>
<File
RelativePath="..\src\include\grid.h"
>
</File>
<File
RelativePath="..\src\frontend\plotting\grid.h"
RelativePath="..\src\misc\hash.h"
>
</File>
<File
@ -1212,11 +1220,11 @@
>
</File>
<File
RelativePath="..\src\frontend\inp.h"
RelativePath="..\src\spicelib\parser\inp.h"
>
</File>
<File
RelativePath="..\src\spicelib\parser\inp.h"
RelativePath="..\src\frontend\inp.h"
>
</File>
<File
@ -1375,6 +1383,10 @@
RelativePath="..\src\include\memory.h"
>
</File>
<File
RelativePath="..\src\misc\mempool.h"
>
</File>
<File
RelativePath="..\src\spicelib\devices\mesa\mesadefs.h"
>
@ -4503,6 +4515,10 @@
RelativePath="..\src\frontend\commands.c"
>
</File>
<File
RelativePath="..\src\frontend\compatmode.c"
>
</File>
<File
RelativePath="..\src\frontend\parser\complete.c"
>
@ -4999,6 +5015,10 @@
RelativePath="..\src\frontend\plotting\grid.c"
>
</File>
<File
RelativePath="..\src\misc\hash.c"
>
</File>
<File
RelativePath="..\src\frontend\hcomp.c"
>
@ -5875,6 +5895,10 @@
RelativePath="..\src\frontend\measure.c"
>
</File>
<File
RelativePath="..\src\misc\mempool.c"
>
</File>
<File
RelativePath="..\src\spicelib\devices\mes\mes.c"
>

Loading…
Cancel
Save