new code for .measurement
This commit is contained in:
parent
4692651211
commit
9f1ee290a4
|
|
@ -95,6 +95,8 @@ libfte_la_SOURCES = \
|
||||||
breakp2.h \
|
breakp2.h \
|
||||||
circuits.c \
|
circuits.c \
|
||||||
circuits.h \
|
circuits.h \
|
||||||
|
compatmode.c \
|
||||||
|
compatmode.h \
|
||||||
cpitf.c \
|
cpitf.c \
|
||||||
cpitf.h \
|
cpitf.h \
|
||||||
define.c \
|
define.c \
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/* New routines to evaluate the .measure cards.
|
/* New routines to evaluate the .measure cards.
|
||||||
Entry point is function get_measure2(), called by fcn do_measure()
|
Entry point is function get_measure2(), called by fcn do_measure()
|
||||||
from measure.c, if line measure.c:25 is commented out.
|
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$
|
$Id$
|
||||||
*/
|
*/
|
||||||
|
|
@ -14,12 +14,9 @@
|
||||||
|
|
||||||
#include "vectors.h"
|
#include "vectors.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include "dotcards.h"
|
||||||
#include "com_measure2.h"
|
#include "com_measure2.h"
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#define strcasecmp _stricmp
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MEASUREMENT_OK = 0,
|
MEASUREMENT_OK = 0,
|
||||||
MEASUREMENT_FAILURE = 1
|
MEASUREMENT_FAILURE = 1
|
||||||
|
|
@ -33,42 +30,225 @@ typedef struct measure
|
||||||
char *result;
|
char *result;
|
||||||
|
|
||||||
char *m_vec; // name of the output variable which determines the beginning of the measurement
|
char *m_vec; // name of the output variable which determines the beginning of the measurement
|
||||||
char *m_vec2;
|
char *m_vec2; // second output variable to measure if applicable
|
||||||
int m_rise;
|
int m_rise; // count number of rise events
|
||||||
int m_fall;
|
int m_fall; // count number of fall events
|
||||||
int m_cross;
|
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_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_td; // amount of delay before the measurement should start
|
||||||
double m_from;
|
double m_from; // measure only in a time window - starting time of window
|
||||||
double m_to;
|
double m_to; // measurement window - ending time
|
||||||
double m_at;
|
double m_at; // measure at the specified time
|
||||||
double m_measured;
|
double m_measured; // what we measured
|
||||||
double m_measured_at;
|
double m_measured_at; //* what we measured at the given time
|
||||||
|
|
||||||
} measure;
|
} MEASURE, *MEASUREPTR ;
|
||||||
|
|
||||||
enum AnalysisType {
|
typedef enum AnalysisType {
|
||||||
AT_DELAY, AT_TRIG,
|
AT_UNKNOWN, AT_DELAY, AT_TRIG,
|
||||||
AT_FIND, AT_WHEN,
|
AT_FIND, AT_WHEN,
|
||||||
AT_AVG, AT_MIN, AT_MAX, AT_RMS, AT_PP,
|
AT_AVG, AT_MIN, AT_MAX, AT_RMS, AT_PP,
|
||||||
AT_INTEG, AT_DERIV,
|
AT_INTEG, AT_DERIV,
|
||||||
AT_ERR, AT_ERR1, AT_ERR2, AT_ERR3
|
AT_ERR, AT_ERR1, AT_ERR2, AT_ERR3
|
||||||
};
|
} ANALYSIS_TYPE_T ;
|
||||||
|
|
||||||
/** return precision (either 5 or value of environment variable NGSPICE_MEAS_PRECISION) */
|
/** 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;
|
char *env_ptr;
|
||||||
int precision = 5;
|
int precision = 5;
|
||||||
|
|
||||||
if ( ( env_ptr = getenv("NGSPICE_MEAS_PRECISION") ) ) {
|
if ( ( env_ptr = getenv("NGSPICE_MEAS_PRECISION") ) ) {
|
||||||
precision = atoi(env_ptr);
|
precision = atoi(env_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return precision;
|
return precision;
|
||||||
} /* end measure_get_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 i, first;
|
||||||
int riseCnt = 0;
|
int riseCnt = 0;
|
||||||
|
|
@ -129,7 +309,7 @@ void com_measure_when(struct measure *meas) {
|
||||||
crossCnt =1;
|
crossCnt =1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("");
|
fflush( stdout ) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (first > 1) {
|
if (first > 1) {
|
||||||
|
|
@ -186,7 +366,15 @@ void com_measure_when(struct measure *meas) {
|
||||||
return;
|
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;
|
int i;
|
||||||
double value, pvalue, svalue, psvalue;
|
double value, pvalue, svalue, psvalue;
|
||||||
|
|
@ -224,13 +412,17 @@ void measure_at(struct measure *meas, double at) {
|
||||||
return;
|
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;
|
int i, avgCnt;
|
||||||
struct dvec *d, *dScale;
|
struct dvec *d, *dScale;
|
||||||
|
|
@ -272,7 +464,7 @@ void measure_minMaxAvg( struct measure *meas, int minMax ) {
|
||||||
first =1;
|
first =1;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
switch (minMax) {
|
switch (mFunctionType) {
|
||||||
case AT_MIN: {
|
case AT_MIN: {
|
||||||
if (value <= mValue) {
|
if (value <= mValue) {
|
||||||
mValue = value;
|
mValue = value;
|
||||||
|
|
@ -287,53 +479,195 @@ void measure_minMaxAvg( struct measure *meas, int minMax ) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AT_AVG:
|
case AT_AVG: {
|
||||||
case AT_RMS: {
|
|
||||||
mValue = mValue + value;
|
mValue = mValue + value;
|
||||||
avgCnt ++;
|
avgCnt ++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default :
|
||||||
|
fprintf(cp_err, "Error: improper min/max/avg call.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (minMax)
|
switch (mFunctionType)
|
||||||
{
|
{
|
||||||
case AT_AVG: {
|
case AT_AVG: {
|
||||||
meas->m_measured = (mValue / avgCnt);
|
meas->m_measured = (mValue / avgCnt);
|
||||||
meas->m_measured_at = svalue;
|
meas->m_measured_at = svalue;
|
||||||
break;
|
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_MIN:
|
||||||
case AT_MAX: {
|
case AT_MAX: {
|
||||||
meas->m_measured = mValue;
|
meas->m_measured = mValue;
|
||||||
meas->m_measured_at = mValueAt;
|
meas->m_measured_at = mValueAt;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default :
|
||||||
|
fprintf(cp_err, "Error: improper min/max/avg call.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
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):
|
// RMS (root mean squared):
|
||||||
// Calculates the square root of the area under the 'out_var2' curve
|
// Calculates the square root of the area under the 'out_var2' curve
|
||||||
// divided be the period of interest
|
// divided be the period of interest
|
||||||
|
measure_rms_integral(meas,AT_RMS) ;
|
||||||
return;
|
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
|
// INTEGRAL INTEG
|
||||||
|
measure_rms_integral(meas,AT_INTEG) ;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* still some more work to do.... */
|
||||||
void measure_deriv( ) {
|
void measure_deriv( ) {
|
||||||
// DERIVATIVE DERIV
|
// DERIVATIVE DERIV
|
||||||
return;
|
return;
|
||||||
|
|
@ -356,13 +690,6 @@ void measure_ERR3( ) {
|
||||||
return;
|
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( ) {
|
void com_dotmeasure( ) {
|
||||||
|
|
||||||
|
|
@ -373,20 +700,38 @@ void com_dotmeasure( ) {
|
||||||
return;
|
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)
|
if(varname == NULL)
|
||||||
return 1;
|
return TRUE;
|
||||||
d = vec_get(vec);
|
d = vec_get(varname);
|
||||||
if (d == NULL)
|
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;
|
int pCnt;
|
||||||
char *p, *pName, *pValue;
|
char *p, *pName, *pValue;
|
||||||
|
|
@ -475,7 +820,17 @@ int measure_parse_stdParams (struct measure *meas, wordlist *wl, wordlist *wlBre
|
||||||
return 1;
|
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;
|
int pCnt;
|
||||||
char *p, *pName, *pVal;
|
char *p, *pName, *pVal;
|
||||||
|
|
@ -497,9 +852,7 @@ int measure_parse_find (struct measure *meas, wordlist *wl, wordlist *wlBreak, c
|
||||||
p = wl->wl_word;
|
p = wl->wl_word;
|
||||||
|
|
||||||
if (pCnt == 0 ) {
|
if (pCnt == 0 ) {
|
||||||
// meas->m_vec =(char *)tmalloc(strlen(wl->wl_word)+1);
|
meas->m_vec= cp_unquote(wl->wl_word);
|
||||||
// strcpy(meas->m_vec, cp_unquote(wl->wl_word));
|
|
||||||
meas->m_vec= cp_unquote(wl->wl_word);
|
|
||||||
} else if (pCnt == 1) {
|
} else if (pCnt == 1) {
|
||||||
|
|
||||||
pName = strtok(p, "=");
|
pName = strtok(p, "=");
|
||||||
|
|
@ -537,7 +890,16 @@ int measure_parse_find (struct measure *meas, wordlist *wl, wordlist *wlBreak, c
|
||||||
return 1;
|
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;
|
int pCnt;
|
||||||
char *p, *pVar1, *pVar2;
|
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;
|
int pcnt;
|
||||||
char *p;
|
char *p;
|
||||||
|
|
@ -634,9 +1007,21 @@ int measure_parse_trigtarg (struct measure *meas, wordlist *words, wordlist *wlT
|
||||||
return 1;
|
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
|
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;
|
wordlist *words, *wlTarg, *wlWhen;
|
||||||
char errbuf[100];
|
char errbuf[100];
|
||||||
char *mType = NULL; // analysis type
|
char *mType = NULL; // analysis type
|
||||||
|
|
@ -673,7 +1058,7 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck)
|
||||||
return MEASUREMENT_FAILURE;
|
return MEASUREMENT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
precision = get_measure_precision() ;
|
precision = measure_get_precision() ;
|
||||||
wl_cnt = 0;
|
wl_cnt = 0;
|
||||||
while (words) {
|
while (words) {
|
||||||
|
|
||||||
|
|
@ -687,43 +1072,14 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck)
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
mFunction = cp_unquote(words->wl_word);
|
mFunctionType = measure_function_type(words->wl_word);
|
||||||
// Functions
|
if ( mFunctionType == AT_UNKNOWN ){
|
||||||
if (strcasecmp(mFunction,"DELAY")==0)
|
if(!(autocheck)){
|
||||||
mFunctionType = AT_DELAY;
|
printf("\tmeasure '%s' failed\n", mName);
|
||||||
else if (strcasecmp(mFunction,"TRIG")==0)
|
printf("Error: measure %s :\n", mName);
|
||||||
mFunctionType = AT_DELAY;
|
printf("\tno such function as '%s'\n", words->wl_word);
|
||||||
else if (strcasecmp(mFunction,"FIND")==0)
|
}
|
||||||
mFunctionType = AT_FIND;
|
return MEASUREMENT_FAILURE;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -771,7 +1127,7 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck)
|
||||||
case AT_TRIG:
|
case AT_TRIG:
|
||||||
{
|
{
|
||||||
// trig parameters
|
// trig parameters
|
||||||
measure *measTrig, *measTarg;
|
MEASUREPTR measTrig, measTarg;
|
||||||
measTrig = (struct measure*)tmalloc(sizeof(struct measure));
|
measTrig = (struct measure*)tmalloc(sizeof(struct measure));
|
||||||
measTarg = (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:
|
case AT_FIND:
|
||||||
{
|
{
|
||||||
measure *meas, *measFind;
|
MEASUREPTR meas, measFind;
|
||||||
meas = (struct measure*)tmalloc(sizeof(struct measure));
|
meas = (struct measure*)tmalloc(sizeof(struct measure));
|
||||||
measFind = (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:
|
case AT_WHEN:
|
||||||
{
|
{
|
||||||
measure *meas;
|
MEASUREPTR meas;
|
||||||
meas = (struct measure*)tmalloc(sizeof(struct measure));
|
meas = (struct measure*)tmalloc(sizeof(struct measure));
|
||||||
|
|
||||||
if (measure_parse_when(meas, words, errbuf) ==0) {
|
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;
|
return MEASUREMENT_OK;
|
||||||
}
|
}
|
||||||
case AT_RMS:
|
case AT_RMS:
|
||||||
printf("\tmeasure '%s' failed\n", mName);
|
case AT_INTEG:
|
||||||
printf("Error: measure %s :\n", mName);
|
{
|
||||||
printf("\tfunction '%s' currently not supported\n", mFunction);
|
// trig parameters
|
||||||
break;
|
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:
|
case AT_AVG:
|
||||||
{
|
{
|
||||||
// trig parameters
|
// trig parameters
|
||||||
measure *meas;
|
MEASUREPTR meas;
|
||||||
meas = (struct measure*)tmalloc(sizeof(struct measure));
|
meas = (struct measure*)tmalloc(sizeof(struct measure));
|
||||||
|
|
||||||
if (measure_parse_trigtarg(meas, words , NULL, "trig", errbuf)==0) {
|
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:
|
case AT_MAX:
|
||||||
{
|
{
|
||||||
// trig parameters
|
// trig parameters
|
||||||
measure *measTrig;
|
MEASUREPTR measTrig;
|
||||||
measTrig = (struct measure*)tmalloc(sizeof(struct measure));
|
measTrig = (struct measure*)tmalloc(sizeof(struct measure));
|
||||||
|
|
||||||
if (measure_parse_trigtarg(measTrig, words , NULL, "trig", errbuf)==0) {
|
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;
|
double minValue, maxValue;
|
||||||
|
|
||||||
measure *measTrig;
|
MEASUREPTR measTrig;
|
||||||
measTrig = (struct measure*)tmalloc(sizeof(struct measure));
|
measTrig = (struct measure*)tmalloc(sizeof(struct measure));
|
||||||
|
|
||||||
if (measure_parse_trigtarg(measTrig, words , NULL, "trig", errbuf)==0) {
|
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);
|
*result = (maxValue - minValue);
|
||||||
return MEASUREMENT_OK;
|
return MEASUREMENT_OK;
|
||||||
}
|
}
|
||||||
case AT_INTEG:
|
|
||||||
case AT_DERIV:
|
case AT_DERIV:
|
||||||
case AT_ERR:
|
case AT_ERR:
|
||||||
case AT_ERR1:
|
case AT_ERR1:
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,9 @@
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
int get_measure_precision(void) ;
|
extern int get_measure_precision(void) ;
|
||||||
/* void com_measure2(wordlist *wl); */
|
/* void com_measure2(wordlist *wl); */
|
||||||
int get_measure2(wordlist *wl,double *result,char *out_line, bool auto_check) ;
|
extern int get_measure2(wordlist *wl,double *result,char *out_line, bool auto_check) ;
|
||||||
|
extern int measure_extract_variables( char *line ) ;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,13 @@ $Id$
|
||||||
#include "variable.h"
|
#include "variable.h"
|
||||||
#include "fourier.h"
|
#include "fourier.h"
|
||||||
#include "breakp2.h"
|
#include "breakp2.h"
|
||||||
|
#include "com_measure2.h"
|
||||||
|
|
||||||
/* Extract all the .save lines */
|
/* Extract all the .save lines */
|
||||||
|
|
||||||
static void fixdotplot(wordlist *wl);
|
static void fixdotplot(wordlist *wl);
|
||||||
static void fixdotprint(wordlist *wl);
|
static void fixdotprint(wordlist *wl);
|
||||||
static char * fixem(char *string);
|
static char * fixem(char *string);
|
||||||
static wordlist * gettoks(char *s);
|
|
||||||
|
|
||||||
|
|
||||||
static struct plot *
|
static struct plot *
|
||||||
|
|
@ -90,6 +90,7 @@ ft_savedotargs(void)
|
||||||
static wordlist all = { "all", NULL };
|
static wordlist all = { "all", NULL };
|
||||||
int isaplot;
|
int isaplot;
|
||||||
int i;
|
int i;
|
||||||
|
int status;
|
||||||
|
|
||||||
if (!ft_curckt) /* Shouldn't happen. */
|
if (!ft_curckt) /* Shouldn't happen. */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -137,15 +138,10 @@ ft_savedotargs(void)
|
||||||
com_save2(w, "TRAN"); /* A hack */
|
com_save2(w, "TRAN"); /* A hack */
|
||||||
}
|
}
|
||||||
} else if (ciprefix(".measure", s)) {
|
} else if (ciprefix(".measure", s)) {
|
||||||
(void) gettok(&s);
|
status = measure_extract_variables( s ) ;
|
||||||
name = gettok(&s);
|
if(!(status)){
|
||||||
(void) gettok(&s);
|
some = 1;
|
||||||
(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);
|
|
||||||
} else if (ciprefix(".op", s)) {
|
} else if (ciprefix(".op", s)) {
|
||||||
some = 1;
|
some = 1;
|
||||||
com_save2(&all, "OP");
|
com_save2(&all, "OP");
|
||||||
|
|
@ -157,6 +153,24 @@ ft_savedotargs(void)
|
||||||
return some;
|
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.
|
/* 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
|
* 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
|
* 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)
|
gettoks(char *s)
|
||||||
{
|
{
|
||||||
char *t;
|
char *t;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
void ft_dotsaves(void);
|
void ft_dotsaves(void);
|
||||||
int ft_savedotargs(void);
|
int ft_savedotargs(void);
|
||||||
int ft_cktcoms(bool terse);
|
int ft_cktcoms(bool terse);
|
||||||
|
wordlist *gettoks(char *s);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,7 @@
|
||||||
void winmessage(char* new_msg);
|
void winmessage(char* new_msg);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define OLD_WAY /* do not use functions from com_measure2.c */
|
|
||||||
|
|
||||||
#ifndef OLD_WAY
|
|
||||||
static wordlist *measure_parse_line( char *line ) ;
|
static wordlist *measure_parse_line( char *line ) ;
|
||||||
#endif
|
|
||||||
|
|
||||||
static bool measure_valid[20000];/* TRUE: if measurement no. [xxx] has been done successfully
|
static bool measure_valid[20000];/* TRUE: if measurement no. [xxx] has been done successfully
|
||||||
(not used anywhere)*/
|
(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)*/
|
no output generated (if option autostop is set)*/
|
||||||
static bool measures_passed; /* TRUE: stop simulation (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
|
static bool
|
||||||
chkAnalysisType( char *an_type ) {
|
chkAnalysisType( char *an_type ) {
|
||||||
|
|
@ -299,49 +45,13 @@ chkAnalysisType( char *an_type ) {
|
||||||
else return TRUE;
|
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.
|
/* Gets pointer to double value after 'xxx=' and advances pointer of *line.
|
||||||
On error returns FALSE. */
|
On error returns FALSE. */
|
||||||
static bool
|
static bool
|
||||||
get_double_value(
|
get_double_value(
|
||||||
char **line, /*in|out: pointer to line to be parsed */
|
char **line, /*in|out: pointer to line to be parsed */
|
||||||
char *name, /*in: xxx e.g. 'val' from 'val=0.5' */
|
char *name, /*in: xxx e.g. 'val' from 'val=0.5' */
|
||||||
double *value /*out: return value (e.g. 0.5) from 'val=0.5'*/
|
double *value /*out: return value (e.g. 0.5) from 'val=0.5'*/
|
||||||
) {
|
) {
|
||||||
char *token = gettok(line);
|
char *token = gettok(line);
|
||||||
|
|
@ -375,235 +85,6 @@ get_double_value(
|
||||||
return return_val;
|
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.
|
/* Entry point for .meas evaluation.
|
||||||
Called in fcn dosim() from runcoms.c:335, after simulation is finished
|
Called in fcn dosim() from runcoms.c:335, after simulation is finished
|
||||||
|
|
@ -624,7 +105,7 @@ do_measure(
|
||||||
double result = 0;
|
double result = 0;
|
||||||
bool first_time = TRUE;
|
bool first_time = TRUE;
|
||||||
wordlist *measure_word_list ;
|
wordlist *measure_word_list ;
|
||||||
int precision = get_measure_precision();
|
int precision = measure_get_precision() ;
|
||||||
|
|
||||||
just_chk_meas = chk_only;
|
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
|
measurement type trig|delay|param|expr|avg|mean|max|min|rms|integ(ral)|when
|
||||||
|
|
||||||
The measurement type determines how to continue the .meas card.
|
The measurement type determines how to continue the .meas card.
|
||||||
trig|delay are handled in fcn do_delay_measurement(), param|expr are skipped
|
param|expr are skipped in first pass through .meas cards and are treated in second pass,
|
||||||
in first pass through .meas cards and are treated in second pass,
|
all others are treated in fcn get_measure2() (com_measure2.c).
|
||||||
all others are treated in fcn do_other_measurement().
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* first pass through .meas cards: evaluate everything except param|expr */
|
/* first pass through .meas cards: evaluate everything except param|expr */
|
||||||
|
|
@ -683,42 +163,27 @@ do_measure(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef OLD_WAY
|
/* New way of processing measure statements using common code
|
||||||
if ( strcmp( meastype, "trig" ) == 0 || strcmp( meastype, "delay" ) == 0 ) {
|
in fcn get_measure2() (com_measure2.c)*/
|
||||||
if ( do_delay_measurement( resname, out_line, line, meas_card->li_line, idx++, &result ) && just_chk_meas != TRUE ) {
|
out_line[0] = EOS ;
|
||||||
nupa_add_param( resname, result );
|
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;
|
||||||
}
|
}
|
||||||
}
|
wl_free( measure_word_list ) ;
|
||||||
else if ( strcmp( meastype, "avg" ) == 0 || strcmp( meastype, "mean" ) == 0 ||
|
} else {
|
||||||
strcmp( meastype, "max" ) == 0 || strcmp( meastype, "min" ) == 0 ||
|
measure_valid[idx++] = FALSE;
|
||||||
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 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
measures_passed = 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 = alloc(struct line);
|
||||||
newcard->li_line = strdup(out_line);
|
newcard->li_line = strdup(out_line);
|
||||||
newcard->li_next = NULL;
|
newcard->li_next = NULL;
|
||||||
|
|
@ -731,7 +196,7 @@ do_measure(
|
||||||
|
|
||||||
txfree(an_type); txfree(resname); txfree(meastype);
|
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 ) {
|
if ( idx >= 20000 ) {
|
||||||
fprintf( stderr, "ERROR: number of measurements exceeds 20,000!\nAborting...\n" );
|
fprintf( stderr, "ERROR: number of measurements exceeds 20,000!\nAborting...\n" );
|
||||||
#ifdef HAS_WINDOWS
|
#ifdef HAS_WINDOWS
|
||||||
|
|
@ -739,8 +204,10 @@ do_measure(
|
||||||
#endif
|
#endif
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* end of for loop (first pass through .meas lines) */
|
} /* end of for loop (first pass through .meas lines) */
|
||||||
|
|
||||||
|
|
||||||
/* second pass through .meas cards: now do param|expr .meas statements */
|
/* second pass through .meas cards: now do param|expr .meas statements */
|
||||||
newcard = meas_results;
|
newcard = meas_results;
|
||||||
for ( meas_card = ft_curckt->ci_meas; meas_card != NULL; meas_card = meas_card->li_next ) {
|
for ( meas_card = ft_curckt->ci_meas; meas_card != NULL; meas_card = meas_card->li_next ) {
|
||||||
|
|
@ -777,7 +244,7 @@ do_measure(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( just_chk_meas != TRUE ) fprintf( stdout, "%-15s=", resname );
|
if ( just_chk_meas != TRUE ) fprintf( stdout, "%-20s=", resname );
|
||||||
|
|
||||||
if ( just_chk_meas != TRUE ) {
|
if ( just_chk_meas != TRUE ) {
|
||||||
ok = nupa_eval( meas_card->li_line, meas_card->li_linenum );
|
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" );
|
if ( just_chk_meas != TRUE ) fprintf( stdout, " failed\n" );
|
||||||
}
|
}
|
||||||
else {
|
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 );
|
nupa_add_param( resname, result );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -830,7 +297,8 @@ check_autostop( char* what ) {
|
||||||
return flag;
|
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 */
|
int len ; /* length of string */
|
||||||
wordlist *wl ; /* build a word list - head of list */
|
wordlist *wl ; /* build a word list - head of list */
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,7 @@ typedef struct _ttdico {
|
||||||
char **dynrefptr;
|
char **dynrefptr;
|
||||||
// char category[Maxline]; /* category of each line */
|
// char category[Maxline]; /* category of each line */
|
||||||
char *dyncategory;
|
char *dyncategory;
|
||||||
|
int hspice_compatibility; /* allow hspice keywords */
|
||||||
} tdico;
|
} tdico;
|
||||||
|
|
||||||
void initdico(tdico * dico);
|
void initdico(tdico * dico);
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,7 @@
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
#include "numparam.h"
|
#include "numparam.h"
|
||||||
#include "ngspice.h"
|
#include "ngspice.h"
|
||||||
|
#include "../compatmode.h"
|
||||||
#ifdef _MSC_VER
|
|
||||||
#define strcasecmp _stricmp
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* random numbers in /maths/misc/randnumb.c */
|
/* random numbers in /maths/misc/randnumb.c */
|
||||||
extern double gauss();
|
extern double gauss();
|
||||||
|
|
@ -158,6 +155,8 @@ void
|
||||||
initdico (tdico * dico)
|
initdico (tdico * dico)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
COMPATMODE_T compat_mode;
|
||||||
|
|
||||||
dico->nbd = 0;
|
dico->nbd = 0;
|
||||||
sini(dico->option,sizeof(dico->option)-4);
|
sini(dico->option,sizeof(dico->option)-4);
|
||||||
sini(dico->srcfile,sizeof(dico->srcfile)-4);
|
sini(dico->srcfile,sizeof(dico->srcfile)-4);
|
||||||
|
|
@ -172,6 +171,12 @@ initdico (tdico * dico)
|
||||||
dico->tos = 0;
|
dico->tos = 0;
|
||||||
dico->stack[dico->tos] = 0; /* global data beneath */
|
dico->stack[dico->tos] = 0; /* global data beneath */
|
||||||
initkeys ();
|
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 */
|
/* local semantics for parameters inside a subckt */
|
||||||
|
|
@ -1437,7 +1442,11 @@ scanline (tdico * dico, char *s, char *r, unsigned char err)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pscopy (t, s, i + 1, k - i - 1);
|
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;
|
i = k;
|
||||||
if (!err)
|
if (!err)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
#define _BOOL_H
|
#define _BOOL_H
|
||||||
|
|
||||||
typedef unsigned char bool;
|
typedef unsigned char bool;
|
||||||
|
typedef int BOOL ;
|
||||||
|
|
||||||
#define BOOLEAN int
|
#define BOOLEAN int
|
||||||
#define TRUE 1
|
#define TRUE 1
|
||||||
|
|
|
||||||
|
|
@ -71,9 +71,17 @@
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#define DEBUGMSG(textargs) printf(textargs)
|
#define DEBUGMSG(textargs) printf(textargs)
|
||||||
#else
|
#define DS(name_xz) { name_xz }
|
||||||
|
#define DBGDEFINE(func_xz) func_xz
|
||||||
|
#else /* ! DEBUG */
|
||||||
#define DEBUGMSG(testargs)
|
#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. */
|
/* Macro that queries the system to find the process time. */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,12 @@ libmisc_la_SOURCES = \
|
||||||
alloc.h \
|
alloc.h \
|
||||||
dup2.c \
|
dup2.c \
|
||||||
dup2.h \
|
dup2.h \
|
||||||
|
hash.h \
|
||||||
|
hash.c \
|
||||||
ivars.c \
|
ivars.c \
|
||||||
ivars.h \
|
ivars.h \
|
||||||
|
mempool.c \
|
||||||
|
mempool.h \
|
||||||
mktemp.c \
|
mktemp.c \
|
||||||
mktemp.h \
|
mktemp.h \
|
||||||
printnum.c \
|
printnum.c \
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,7 @@ typedef pthread_t threadId_t;
|
||||||
#include <spicelib/analysis/analysis.h>
|
#include <spicelib/analysis/analysis.h>
|
||||||
#include <misc/ivars.h>
|
#include <misc/ivars.h>
|
||||||
#include <frontend/resource.h>
|
#include <frontend/resource.h>
|
||||||
|
#include <frontend/com_measure2.h>
|
||||||
#ifndef _MSC_VER /* avoid second definition of VT_BOOL */
|
#ifndef _MSC_VER /* avoid second definition of VT_BOOL */
|
||||||
#include <frontend/variable.h>
|
#include <frontend/variable.h>
|
||||||
#else
|
#else
|
||||||
|
|
@ -2115,7 +2116,7 @@ static int listTriggers TCL_CMDPROCARGS(clientData,interp,argc,argv){
|
||||||
static int tmeasure TCL_CMDPROCARGS(clientData,interp,argc,argv){
|
static int tmeasure TCL_CMDPROCARGS(clientData,interp,argc,argv){
|
||||||
|
|
||||||
wordlist *wl= NULL;
|
wordlist *wl= NULL;
|
||||||
float mvalue;
|
double mvalue;
|
||||||
|
|
||||||
if (argc <= 2) {
|
if (argc <= 2) {
|
||||||
Tcl_SetResult(interp, "Wrong # args. spice::listTriggers",TCL_STATIC);
|
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);
|
wl =wl_build((char **)argv);
|
||||||
|
|
||||||
mvalue = get_measure2(wl);
|
get_measure2(wl,&mvalue,NULL,FALSE);
|
||||||
|
|
||||||
printf(" %e \n", mvalue);
|
printf(" %e \n", mvalue);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ Global
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Debug|Win32.ActiveCfg = Debug|Win32
|
{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}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
{83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Release|Win32.ActiveCfg = Release|Win32
|
{83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Release|Win32.ActiveCfg = Debug|Win32
|
||||||
{83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Release|Win32.Build.0 = Release|Win32
|
{83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Release|Win32.Build.0 = Debug|Win32
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
||||||
|
|
@ -819,6 +819,10 @@
|
||||||
RelativePath="..\src\frontend\commands.h"
|
RelativePath="..\src\frontend\commands.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\src\frontend\compatmode.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\src\frontend\parser\complete.h"
|
RelativePath="..\src\frontend\parser\complete.h"
|
||||||
>
|
>
|
||||||
|
|
@ -1103,12 +1107,16 @@
|
||||||
RelativePath="..\src\frontend\plotting\graphdb.h"
|
RelativePath="..\src\frontend\plotting\graphdb.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\src\frontend\plotting\grid.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\src\include\grid.h"
|
RelativePath="..\src\include\grid.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\src\frontend\plotting\grid.h"
|
RelativePath="..\src\misc\hash.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
|
|
@ -1212,11 +1220,11 @@
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\src\frontend\inp.h"
|
RelativePath="..\src\spicelib\parser\inp.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\src\spicelib\parser\inp.h"
|
RelativePath="..\src\frontend\inp.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
|
|
@ -1375,6 +1383,10 @@
|
||||||
RelativePath="..\src\include\memory.h"
|
RelativePath="..\src\include\memory.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\src\misc\mempool.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\src\spicelib\devices\mesa\mesadefs.h"
|
RelativePath="..\src\spicelib\devices\mesa\mesadefs.h"
|
||||||
>
|
>
|
||||||
|
|
@ -4503,6 +4515,10 @@
|
||||||
RelativePath="..\src\frontend\commands.c"
|
RelativePath="..\src\frontend\commands.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\src\frontend\compatmode.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\src\frontend\parser\complete.c"
|
RelativePath="..\src\frontend\parser\complete.c"
|
||||||
>
|
>
|
||||||
|
|
@ -4999,6 +5015,10 @@
|
||||||
RelativePath="..\src\frontend\plotting\grid.c"
|
RelativePath="..\src\frontend\plotting\grid.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\src\misc\hash.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\src\frontend\hcomp.c"
|
RelativePath="..\src\frontend\hcomp.c"
|
||||||
>
|
>
|
||||||
|
|
@ -5875,6 +5895,10 @@
|
||||||
RelativePath="..\src\frontend\measure.c"
|
RelativePath="..\src\frontend\measure.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\src\misc\mempool.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\src\spicelib\devices\mes\mes.c"
|
RelativePath="..\src\spicelib\devices\mes\mes.c"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue