.meas patches by Bill Swartz added
This commit is contained in:
parent
b6a05e9095
commit
b399caf9bc
|
|
@ -2,6 +2,11 @@
|
|||
* src/frontend/resource.c: applied patch from Thomas D. Dean to remove
|
||||
the limit warning.
|
||||
|
||||
2009-08-08 Holger Vogt
|
||||
* measure.c, com_measure2.c, com_measure2.h, xpressn.c:
|
||||
Patches from Bill Swartz added
|
||||
* examples/inverter3.sp: test of new features
|
||||
|
||||
2009-08-08 Holger Vogt
|
||||
* measure.c: add more comments
|
||||
* example/func_cap.sp, inverter.sp, inverter2.sp: hint to
|
||||
|
|
|
|||
|
|
@ -79,12 +79,15 @@ c1 out gnd 220fF
|
|||
.tran 1ps 4ns
|
||||
|
||||
.meas tran inv_delay trig v(in) val='vp/2' fall=1 targ v(out) val='vp/2' rise=1
|
||||
.meas tran out_slew trig v(out) val='0.2*vp' rise=1 targ v(out) val='0.8*vp' rise=1
|
||||
*.meas tran test_data1 trig AT = 1n targ v(out) val='vp/2' rise=3
|
||||
*not yet implemented
|
||||
*.meas tran test_data2 trig v(in) val='vp/2' fall=1 targ AT = 2n
|
||||
.meas tran out_slew trig v(out) val='0.2*vp' rise=2 targ v(out) val='0.8*vp' rise=2
|
||||
.meas tran delay_chk param='(inv_delay < 100ps) ? 1 : 0'
|
||||
.meas tran skew when v(out)=0.6
|
||||
.meas tran skew2 when v(out)=skew_meas
|
||||
.meas tran skew3 when v(out)=skew_meas fall=2 *fall is ignored
|
||||
*.meas tran skew when v(out)=v(in) not implemented
|
||||
*.meas tran skew3 when v(out)=skew_meas fall=2
|
||||
*.meas tran skew4 FIND v(out) AT=2n
|
||||
|
||||
.control
|
||||
run
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
/* 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.
|
||||
|
||||
$Id$
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <ngspice.h>
|
||||
#include <memory.h>
|
||||
|
|
@ -7,11 +14,20 @@
|
|||
|
||||
#include "vectors.h"
|
||||
#include <math.h>
|
||||
#include "com_measure2.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
MEASUREMENT_OK = 0,
|
||||
MEASUREMENT_FAILURE = 1
|
||||
} MEASURE_VAL_T ;
|
||||
|
||||
#define MEASURE_DEFAULT -1
|
||||
#define MEASURE_LAST_TRANSITION -2
|
||||
|
||||
typedef struct measure
|
||||
{
|
||||
char *result;
|
||||
|
|
@ -21,13 +37,13 @@ typedef struct measure
|
|||
int m_rise;
|
||||
int m_fall;
|
||||
int m_cross;
|
||||
float m_val; // value of the m_ver at which the counter for crossing, rises or falls is incremented by one
|
||||
float m_td; // amount of delay before the measurement should start
|
||||
float m_from;
|
||||
float m_to;
|
||||
float m_at;
|
||||
float m_measured;
|
||||
float m_measured_at;
|
||||
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;
|
||||
|
||||
} measure;
|
||||
|
||||
|
|
@ -39,15 +55,30 @@ enum AnalysisType {
|
|||
AT_ERR, AT_ERR1, AT_ERR2, AT_ERR3
|
||||
};
|
||||
|
||||
/** return precision (either 5 or value of environment variable NGSPICE_MEAS_PRECISION) */
|
||||
int get_measure_precision(void)
|
||||
{
|
||||
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) {
|
||||
|
||||
int i, first;
|
||||
int riseCnt =0;
|
||||
int fallCnt =0;
|
||||
int crossCnt =0;
|
||||
int riseCnt = 0;
|
||||
int fallCnt = 0;
|
||||
int crossCnt = 0;
|
||||
int section = -1;
|
||||
float value, prevValue;
|
||||
float timeValue, prevTimeValue;
|
||||
int measurement_pending;
|
||||
int init_measured_value;
|
||||
double value, prevValue;
|
||||
double timeValue, prevTimeValue;
|
||||
|
||||
enum ValSide { S_ABOVE_VAL, S_BELOW_VAL };
|
||||
enum ValEdge { E_RISING, E_FALLING };
|
||||
|
|
@ -70,6 +101,8 @@ void com_measure_when(struct measure *meas) {
|
|||
prevValue =0;
|
||||
prevTimeValue =0;
|
||||
first =0;
|
||||
measurement_pending=0;
|
||||
init_measured_value=1;
|
||||
|
||||
for (i=0; i < d->v_length; i++) {
|
||||
|
||||
|
|
@ -105,18 +138,41 @@ void com_measure_when(struct measure *meas) {
|
|||
section = S_ABOVE_VAL;
|
||||
crossCnt++;
|
||||
riseCnt++;
|
||||
if( meas->m_fall != MEASURE_LAST_TRANSITION ){
|
||||
/* we can measure rise/cross transition if the user
|
||||
* has not requested a last fall transition */
|
||||
measurement_pending=1;
|
||||
}
|
||||
|
||||
} else if ( (section == S_ABOVE_VAL) && (value <= meas->m_val) ) {
|
||||
section = S_BELOW_VAL;
|
||||
crossCnt++;
|
||||
fallCnt++;
|
||||
if( meas->m_rise != MEASURE_LAST_TRANSITION ){
|
||||
/* we can measure fall/cross transition if the user
|
||||
* has not requested a last rise transition */
|
||||
measurement_pending=1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((crossCnt == meas->m_cross) || (riseCnt == meas->m_rise) || (fallCnt == meas->m_fall)) {
|
||||
meas->m_measured = prevTimeValue + (meas->m_val - prevValue) * (timeValue - prevTimeValue) / (value - prevValue);
|
||||
return;
|
||||
|
||||
/* user requested an exact match of cross, rise, or fall
|
||||
* exit when we meet condition */
|
||||
meas->m_measured = prevTimeValue + (meas->m_val - prevValue) * (timeValue - prevTimeValue) / (value - prevValue);
|
||||
return;
|
||||
}
|
||||
if ( measurement_pending ){
|
||||
if( (meas->m_cross == MEASURE_DEFAULT) && (meas->m_rise == MEASURE_DEFAULT) && (meas->m_fall == MEASURE_DEFAULT) ){
|
||||
/* user didn't request any option, return the first possible case */
|
||||
meas->m_measured = prevTimeValue + (meas->m_val - prevValue) * (timeValue - prevTimeValue) / (value - prevValue);
|
||||
return;
|
||||
} else if( (meas->m_cross == MEASURE_LAST_TRANSITION) || (meas->m_rise == MEASURE_LAST_TRANSITION) || (meas->m_fall == MEASURE_LAST_TRANSITION) ){
|
||||
meas->m_measured = prevTimeValue + (meas->m_val - prevValue) * (timeValue - prevTimeValue) / (value - prevValue);
|
||||
/* no return - look for last */
|
||||
init_measured_value=0;
|
||||
}
|
||||
measurement_pending=0;
|
||||
}
|
||||
}
|
||||
first ++;
|
||||
|
||||
|
|
@ -124,14 +180,16 @@ void com_measure_when(struct measure *meas) {
|
|||
prevTimeValue = timeValue;
|
||||
}
|
||||
|
||||
meas->m_measured = 0.0e0;
|
||||
if ( init_measured_value ){
|
||||
meas->m_measured = 0.0e0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void measure_at(struct measure *meas, float at) {
|
||||
void measure_at(struct measure *meas, double at) {
|
||||
|
||||
int i;
|
||||
float value, pvalue, svalue, psvalue;
|
||||
double value, pvalue, svalue, psvalue;
|
||||
struct dvec *d, *dScale;
|
||||
|
||||
psvalue = pvalue = 0;
|
||||
|
|
@ -176,7 +234,7 @@ void measure_minMaxAvg( struct measure *meas, int minMax ) {
|
|||
|
||||
int i, avgCnt;
|
||||
struct dvec *d, *dScale;
|
||||
float value, svalue, mValue, mValueAt;
|
||||
double value, svalue, mValue, mValueAt;
|
||||
int first;
|
||||
|
||||
mValue =0;
|
||||
|
|
@ -298,8 +356,8 @@ void measure_ERR3( ) {
|
|||
return;
|
||||
}
|
||||
|
||||
void measure_errMessage(char *mName, char *mFunction, char *trigTarg, char *errMsg) {
|
||||
|
||||
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);
|
||||
|
|
@ -318,7 +376,9 @@ void com_dotmeasure( ) {
|
|||
int measure_valid_vector(char *vec) {
|
||||
|
||||
struct dvec *d;
|
||||
|
||||
|
||||
if(vec == NULL)
|
||||
return 1;
|
||||
d = vec_get(vec);
|
||||
if (d == NULL)
|
||||
return 0;
|
||||
|
|
@ -332,34 +392,46 @@ int measure_parse_stdParams (struct measure *meas, wordlist *wl, wordlist *wlBre
|
|||
char *p, *pName, *pValue;
|
||||
double *engVal, engVal1;
|
||||
|
||||
pCnt =0;
|
||||
pCnt = 0;
|
||||
while (wl != wlBreak) {
|
||||
p = wl->wl_word;
|
||||
pName = strtok(p, "=");
|
||||
pValue = strtok(NULL, "=");
|
||||
|
||||
if (pValue == NULL) {
|
||||
sprintf(errbuf,"bad syntax of ??\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(engVal = ft_numparse(&pValue, FALSE))) {
|
||||
sprintf(errbuf,"bad syntax of ??\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
engVal1 = *engVal;
|
||||
if (pValue == NULL) {
|
||||
if( strcasecmp(pName,"LAST")==0) {
|
||||
meas->m_cross = MEASURE_LAST_TRANSITION;
|
||||
meas->m_rise = -1;
|
||||
meas->m_fall = -1;
|
||||
pCnt ++;
|
||||
wl = wl->wl_next;
|
||||
continue ;
|
||||
} else {
|
||||
sprintf(errbuf,"bad syntax of ??\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( strcasecmp(pValue,"LAST")==0) {
|
||||
engVal1 = MEASURE_LAST_TRANSITION;
|
||||
} else {
|
||||
if (!(engVal = ft_numparse(&pValue, FALSE))) {
|
||||
sprintf(errbuf,"bad syntax of ??\n");
|
||||
return 0;
|
||||
}
|
||||
engVal1 = *engVal; // What is this ??
|
||||
}
|
||||
|
||||
if(strcasecmp(pName,"RISE")==0) {
|
||||
meas->m_rise = engVal1;
|
||||
meas->m_rise = (int)engVal1;
|
||||
meas->m_fall = -1;
|
||||
meas->m_cross = -1;
|
||||
} else if(strcasecmp(pName,"FALL")==0) {
|
||||
meas->m_fall = engVal1;
|
||||
meas->m_fall = (int)engVal1;
|
||||
meas->m_rise = -1;
|
||||
meas->m_cross = -1;
|
||||
} else if(strcasecmp(pName,"CROSS")==0) {
|
||||
meas->m_cross = engVal1;
|
||||
meas->m_cross = (int)engVal1;
|
||||
meas->m_rise = -1;
|
||||
meas->m_fall = -1;
|
||||
} else if(strcasecmp(pName,"VAL")==0) {
|
||||
|
|
@ -531,10 +603,11 @@ int measure_parse_trigtarg (struct measure *meas, wordlist *words, wordlist *wlT
|
|||
while (words != wlTarg) {
|
||||
p = words->wl_word;
|
||||
|
||||
if (pcnt ==0) {
|
||||
// meas->m_vec =(char *)tmalloc(strlen(words->wl_word)+1);
|
||||
// strcpy(meas->m_vec, cp_unquote(words->wl_word));
|
||||
if ((pcnt == 0) && !ciprefix("at", p)) {
|
||||
meas->m_vec= cp_unquote(words->wl_word);
|
||||
} else if (ciprefix("at", p)) {
|
||||
if (measure_parse_stdParams(meas, words, wlTarg, errbuf) == 0)
|
||||
return 0;
|
||||
} else {
|
||||
|
||||
if (measure_parse_stdParams(meas, words, wlTarg, errbuf) == 0)
|
||||
|
|
@ -561,32 +634,34 @@ int measure_parse_trigtarg (struct measure *meas, wordlist *words, wordlist *wlT
|
|||
return 1;
|
||||
}
|
||||
|
||||
float
|
||||
get_measure2(wordlist *wl)
|
||||
int
|
||||
get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck)
|
||||
{
|
||||
wordlist *words, *wlTarg, *wlWhen;
|
||||
char errbuf[100];
|
||||
char *mType = NULL; // analysis type
|
||||
char *mName = NULL; // name given to the measured output
|
||||
char *mFunction = NULL;
|
||||
int precision; // measurement precision
|
||||
int mFunctionType, wl_cnt;
|
||||
char *p;
|
||||
|
||||
mFunctionType = -1;
|
||||
|
||||
*result = 0.0e0; /* default result */
|
||||
|
||||
if (!wl) {
|
||||
printf("usage: measure .....\n");
|
||||
return 0.0e0;
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
if (!plot_cur || !plot_cur->pl_dvecs || !plot_cur->pl_scale) {
|
||||
fprintf(cp_err, "Error: no vectors available\n");
|
||||
return 0.0e0;
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
if (!ciprefix("tran", plot_cur->pl_typename)) {
|
||||
fprintf(cp_err, "Error: measure limited to transient analysis\n");
|
||||
return 0.0e0;
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
words =wl;
|
||||
|
|
@ -595,10 +670,11 @@ get_measure2(wordlist *wl)
|
|||
|
||||
if (!words) {
|
||||
fprintf(cp_err, "Error: no assignment found.\n");
|
||||
return 0.0e0;
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
wl_cnt = 0;
|
||||
precision = get_measure_precision() ;
|
||||
wl_cnt = 0;
|
||||
while (words) {
|
||||
|
||||
switch(wl_cnt)
|
||||
|
|
@ -647,7 +723,7 @@ get_measure2(wordlist *wl)
|
|||
printf("\tmeasure '%s' failed\n", mName);
|
||||
printf("Error: measure %s :\n", mName);
|
||||
printf("\tno such function as '%s'\n", mFunction);
|
||||
return 0.0e0;
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -672,7 +748,7 @@ get_measure2(wordlist *wl)
|
|||
printf("\tmeasure '%s' failed\n", mName);
|
||||
printf("Error: measure %s :\n", mName);
|
||||
printf("\tinvalid num params\n");
|
||||
return 0.0e0;
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
//------------------------
|
||||
|
|
@ -700,14 +776,14 @@ get_measure2(wordlist *wl)
|
|||
measTarg = (struct measure*)tmalloc(sizeof(struct measure));
|
||||
|
||||
if (measure_parse_trigtarg(measTrig, words , wlTarg, "trig", errbuf)==0) {
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf);
|
||||
return 0.0e0;
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck);
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
if ((measTrig->m_rise == -1) && (measTrig->m_fall == -1) && (measTrig->m_cross == -1)) {
|
||||
sprintf(errbuf,"rise, fall or cross must be given\n");
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf);
|
||||
return 0.0e0;
|
||||
if ((measTrig->m_rise == -1) && (measTrig->m_fall == -1) && (measTrig->m_cross == -1) && (measTrig->m_at == -1)) {
|
||||
sprintf(errbuf,"at, rise, fall or cross must be given\n");
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck);
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
while (words != wlTarg)
|
||||
|
|
@ -717,14 +793,14 @@ get_measure2(wordlist *wl)
|
|||
words = words->wl_next; // skip targ
|
||||
|
||||
if (measure_parse_trigtarg(measTarg, words , NULL, "targ", errbuf)==0) {
|
||||
measure_errMessage(mName, mFunction, "TARG", errbuf);
|
||||
return 0.0e0;
|
||||
measure_errMessage(mName, mFunction, "TARG", errbuf, autocheck);
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
if ((measTarg->m_rise == -1) && (measTarg->m_fall == -1) && (measTarg->m_cross == -1)) {
|
||||
sprintf(errbuf,"rise, fall or cross must be given\n");
|
||||
measure_errMessage(mName, mFunction, "TARG", errbuf);
|
||||
return 0.0e0;
|
||||
if ((measTarg->m_rise == -1) && (measTarg->m_fall == -1) && (measTarg->m_cross == -1)&& (measTarg->m_at == -1)) {
|
||||
sprintf(errbuf,"at, rise, fall or cross must be given\n");
|
||||
measure_errMessage(mName, mFunction, "TARG", errbuf, autocheck);
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
// measure trig
|
||||
|
|
@ -736,22 +812,27 @@ get_measure2(wordlist *wl)
|
|||
|
||||
if (measTrig->m_measured == 0.0e0) {
|
||||
sprintf(errbuf,"out of interval\n");
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf);
|
||||
return 0.0e0;
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck);
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
// measure targ
|
||||
com_measure_when(measTarg);
|
||||
|
||||
if (measTarg->m_measured == 0.0e0) {
|
||||
sprintf(errbuf,"out of interval\n");
|
||||
measure_errMessage(mName, mFunction, "TARG", errbuf);
|
||||
return 0.0e0;
|
||||
measure_errMessage(mName, mFunction, "TARG", errbuf, autocheck);
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
// print results
|
||||
printf("%-20s= %e targ= %e trig= %e\n", mName, (measTarg->m_measured - measTrig->m_measured), measTarg->m_measured, measTrig->m_measured);
|
||||
|
||||
return (measTarg->m_measured - measTrig->m_measured);
|
||||
if( out_line ){
|
||||
sprintf(out_line,"%-20s= %e targ= %e trig= %e\n", mName, (measTarg->m_measured - measTrig->m_measured), measTarg->m_measured, measTrig->m_measured);
|
||||
} else {
|
||||
printf("%-20s= %e targ= %e trig= %e\n", mName, (measTarg->m_measured - measTrig->m_measured), measTarg->m_measured, measTrig->m_measured);
|
||||
}
|
||||
|
||||
*result = (measTarg->m_measured - measTrig->m_measured);
|
||||
return MEASUREMENT_OK;
|
||||
}
|
||||
case AT_FIND:
|
||||
{
|
||||
|
|
@ -760,8 +841,8 @@ get_measure2(wordlist *wl)
|
|||
measFind = (struct measure*)tmalloc(sizeof(struct measure));
|
||||
|
||||
if (measure_parse_find(meas, words, wlWhen, errbuf) == 0) {
|
||||
measure_errMessage(mName, mFunction, "FIND", errbuf);
|
||||
return 0.0e0;
|
||||
measure_errMessage(mName, mFunction, "FIND", errbuf, autocheck);
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
if (meas->m_at == -1 ) {
|
||||
|
|
@ -774,16 +855,16 @@ get_measure2(wordlist *wl)
|
|||
words = words->wl_next; // skip targ
|
||||
|
||||
if (measure_parse_when(measFind, words, errbuf) ==0) {
|
||||
measure_errMessage(mName, mFunction, "WHEN", errbuf);
|
||||
return 0.0e0;
|
||||
measure_errMessage(mName, mFunction, "WHEN", errbuf, autocheck);
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
com_measure_when(measFind);
|
||||
|
||||
if (measFind->m_measured == 0.0e0) {
|
||||
sprintf(errbuf,"out of interval\n");
|
||||
measure_errMessage(mName, mFunction, "WHEN", errbuf);
|
||||
return 0.0e0;
|
||||
measure_errMessage(mName, mFunction, "WHEN", errbuf, autocheck);
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
measure_at(measFind, measFind->m_measured);
|
||||
|
|
@ -795,13 +876,18 @@ get_measure2(wordlist *wl)
|
|||
|
||||
if (meas->m_measured == 0.0e0) {
|
||||
sprintf(errbuf,"out of interval\n");
|
||||
measure_errMessage(mName, mFunction, "WHEN", errbuf);
|
||||
return 0.0e0;
|
||||
measure_errMessage(mName, mFunction, "WHEN", errbuf, autocheck);
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
// print results
|
||||
printf("%-20s= %e\n", mName, meas->m_measured);
|
||||
return meas->m_measured;
|
||||
if( out_line ){
|
||||
sprintf(out_line,"%-20s= %e\n", mName, meas->m_measured);
|
||||
} else {
|
||||
printf("%-20s= %e\n", mName, meas->m_measured);
|
||||
}
|
||||
*result = meas->m_measured;
|
||||
return MEASUREMENT_OK;
|
||||
}
|
||||
case AT_WHEN:
|
||||
{
|
||||
|
|
@ -809,22 +895,27 @@ get_measure2(wordlist *wl)
|
|||
meas = (struct measure*)tmalloc(sizeof(struct measure));
|
||||
|
||||
if (measure_parse_when(meas, words, errbuf) ==0) {
|
||||
measure_errMessage(mName, mFunction, "WHEN", errbuf);
|
||||
return 0.0e0;
|
||||
measure_errMessage(mName, mFunction, "WHEN", errbuf, autocheck);
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
com_measure_when(meas);
|
||||
|
||||
if (meas->m_measured == 0.0e0) {
|
||||
sprintf(errbuf,"out of interval\n");
|
||||
measure_errMessage(mName, mFunction, "WHEN", errbuf);
|
||||
return 0.0e0;
|
||||
measure_errMessage(mName, mFunction, "WHEN", errbuf, autocheck);
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
// print results
|
||||
printf("%-20s= %e\n", mName, meas->m_measured);
|
||||
|
||||
return (meas->m_measured);
|
||||
if( out_line ){
|
||||
sprintf(out_line,"%-20s= %.*e\n", mName, precision, meas->m_measured);
|
||||
} else {
|
||||
printf("%-20s= %e\n", mName, meas->m_measured);
|
||||
}
|
||||
|
||||
*result = meas->m_measured;
|
||||
return MEASUREMENT_OK;
|
||||
}
|
||||
case AT_RMS:
|
||||
printf("\tmeasure '%s' failed\n", mName);
|
||||
|
|
@ -838,8 +929,8 @@ get_measure2(wordlist *wl)
|
|||
meas = (struct measure*)tmalloc(sizeof(struct measure));
|
||||
|
||||
if (measure_parse_trigtarg(meas, words , NULL, "trig", errbuf)==0) {
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf);
|
||||
return 0.0e0;
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck);
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
// measure
|
||||
|
|
@ -847,16 +938,21 @@ get_measure2(wordlist *wl)
|
|||
|
||||
if (meas->m_measured == 0.0e0) {
|
||||
sprintf(errbuf,"out of interval\n");
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf); // ??
|
||||
return 0.0e0;
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck); // ??
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
if (meas->m_at == -1)
|
||||
meas->m_at = 0.0e0;
|
||||
|
||||
// print results
|
||||
printf("%-20s= %e from= %e to= %e\n", mName, meas->m_measured, meas->m_at, meas->m_measured_at);
|
||||
return meas->m_measured;
|
||||
if( out_line ){
|
||||
sprintf(out_line,"%-20s= %e from= %e to= %e\n", mName, meas->m_measured, meas->m_at, meas->m_measured_at);
|
||||
} else {
|
||||
printf("%-20s= %e from= %e to= %e\n", mName, meas->m_measured, meas->m_at, meas->m_measured_at);
|
||||
}
|
||||
*result=meas->m_measured;
|
||||
return MEASUREMENT_OK;
|
||||
|
||||
}
|
||||
case AT_MIN:
|
||||
|
|
@ -867,8 +963,8 @@ get_measure2(wordlist *wl)
|
|||
measTrig = (struct measure*)tmalloc(sizeof(struct measure));
|
||||
|
||||
if (measure_parse_trigtarg(measTrig, words , NULL, "trig", errbuf)==0) {
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf);
|
||||
return 0.0e0;
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck);
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
// measure
|
||||
|
|
@ -880,32 +976,37 @@ get_measure2(wordlist *wl)
|
|||
|
||||
if (measTrig->m_measured == 0.0e0) {
|
||||
sprintf(errbuf,"out of interval\n");
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf); // ??
|
||||
return 0.0e0;
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck); // ??
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
// print results
|
||||
printf("%-20s= %e at= %e\n", mName, measTrig->m_measured, measTrig->m_measured_at);
|
||||
return measTrig->m_measured;
|
||||
if( out_line ){
|
||||
sprintf(out_line,"%-20s= %e at= %e\n", mName, measTrig->m_measured, measTrig->m_measured_at);
|
||||
} else {
|
||||
printf("%-20s= %e at= %e\n", mName, measTrig->m_measured, measTrig->m_measured_at);
|
||||
}
|
||||
*result=measTrig->m_measured;
|
||||
return MEASUREMENT_OK;
|
||||
}
|
||||
case AT_PP:
|
||||
{
|
||||
float minValue, maxValue;
|
||||
double minValue, maxValue;
|
||||
|
||||
measure *measTrig;
|
||||
measTrig = (struct measure*)tmalloc(sizeof(struct measure));
|
||||
|
||||
if (measure_parse_trigtarg(measTrig, words , NULL, "trig", errbuf)==0) {
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf);
|
||||
return 0.0e0;
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck);
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
// measure min
|
||||
measure_minMaxAvg(measTrig, AT_MIN);
|
||||
if (measTrig->m_measured == 0.0e0) {
|
||||
sprintf(errbuf,"out of interval\n");
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf); // ??
|
||||
return 0.0e0;
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck); // ??
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
minValue = measTrig->m_measured;
|
||||
|
||||
|
|
@ -913,14 +1014,19 @@ get_measure2(wordlist *wl)
|
|||
measure_minMaxAvg(measTrig, AT_MAX);
|
||||
if (measTrig->m_measured == 0.0e0) {
|
||||
sprintf(errbuf,"out of interval\n");
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf); // ??
|
||||
return 0.0e0;
|
||||
measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck); // ??
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
maxValue = measTrig->m_measured;
|
||||
|
||||
// print results
|
||||
printf("%-20s= %e from= %e to= %e\n", mName, (maxValue - minValue), measTrig->m_from, measTrig->m_to);
|
||||
return (maxValue - minValue);
|
||||
if( out_line ){
|
||||
sprintf(out_line,"%-20s= %e from= %e to= %e\n", mName, (maxValue - minValue), measTrig->m_from, measTrig->m_to);
|
||||
} else {
|
||||
printf("%-20s= %e from= %e to= %e\n", mName, (maxValue - minValue), measTrig->m_from, measTrig->m_to);
|
||||
}
|
||||
*result = (maxValue - minValue);
|
||||
return MEASUREMENT_OK;
|
||||
}
|
||||
case AT_INTEG:
|
||||
case AT_DERIV:
|
||||
|
|
@ -935,11 +1041,14 @@ get_measure2(wordlist *wl)
|
|||
break;
|
||||
}
|
||||
}
|
||||
return 0.0e0;
|
||||
return MEASUREMENT_FAILURE;
|
||||
}
|
||||
|
||||
void com_measure2(wordlist *wl) {
|
||||
get_measure2(wl);
|
||||
return;
|
||||
}
|
||||
/* I don't know where this routine is called... I want to eliminate it. */
|
||||
/* void com_measure2(wordlist *wl) {
|
||||
double result ;
|
||||
get_measure2(wl,&result,NULL,FALSE);
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
|
||||
#include <config.h>
|
||||
|
||||
void com_measure2(wordlist *wl);
|
||||
float get_measure2(wordlist *wl);
|
||||
int get_measure_precision(void) ;
|
||||
/* void com_measure2(wordlist *wl); */
|
||||
int get_measure2(wordlist *wl,double *result,char *out_line, bool auto_check) ;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -14,31 +14,26 @@
|
|||
#include "variable.h"
|
||||
#include "numparam/numpaif.h"
|
||||
#include "missing_math.h"
|
||||
#include "com_measure2.h"
|
||||
|
||||
#define EOS '\0'
|
||||
|
||||
#ifdef HAS_WINDOWS
|
||||
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)*/
|
||||
static bool just_chk_meas; /* TRUE: only check if measurement can be done successfully,
|
||||
no output generated (if option autostop is set)*/
|
||||
static bool measures_passed; /* TRUE: stop simulation (if option autostop is set)*/
|
||||
|
||||
/** return precision (either 5 or value of environment variable NGSPICE_MEAS_PRECISION) */
|
||||
static int
|
||||
get_measure_precision()
|
||||
{
|
||||
char *env_ptr;
|
||||
int precision = 5;
|
||||
|
||||
if ( ( env_ptr = getenv("NGSPICE_MEAS_PRECISION") ) ) {
|
||||
precision = atoi(env_ptr);
|
||||
}
|
||||
|
||||
return precision;
|
||||
}
|
||||
|
||||
/* returns interpolated time point (char x_or_y='x') or interpolated data value */
|
||||
static double
|
||||
interpolate(
|
||||
|
|
@ -624,15 +619,18 @@ do_measure(
|
|||
) {
|
||||
struct line *meas_card, *meas_results = NULL, *end = NULL, *newcard;
|
||||
char *line, *an_name, *an_type, *resname, *meastype, *str_ptr, out_line[1000];
|
||||
int mindex = 0, ok = 0;
|
||||
int idx = 0, ok = 0;
|
||||
int fail;
|
||||
double result = 0;
|
||||
bool first_time = TRUE;
|
||||
wordlist *measure_word_list ;
|
||||
int precision = get_measure_precision();
|
||||
|
||||
just_chk_meas = chk_only;
|
||||
|
||||
an_name = strdup( what ); /* analysis type, e.g. "tran" */
|
||||
strtolower( an_name );
|
||||
measure_word_list = NULL ;
|
||||
|
||||
/* Evaluating the linked list of .meas cards, assembled from the input deck
|
||||
by fcn inp_spsource() in inp.c:575.
|
||||
|
|
@ -685,8 +683,9 @@ 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, mindex++, &result ) && just_chk_meas != TRUE ) {
|
||||
if ( do_delay_measurement( resname, out_line, line, meas_card->li_line, idx++, &result ) && just_chk_meas != TRUE ) {
|
||||
nupa_add_param( resname, result );
|
||||
}
|
||||
}
|
||||
|
|
@ -694,7 +693,7 @@ do_measure(
|
|||
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, mindex++, &result ) && just_chk_meas != TRUE ) {
|
||||
if ( do_other_measurement( resname, out_line, meastype, line, meas_card->li_line, idx++, &result ) && just_chk_meas != TRUE ) {
|
||||
nupa_add_param( resname, result );
|
||||
}
|
||||
}
|
||||
|
|
@ -706,7 +705,20 @@ do_measure(
|
|||
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;
|
||||
|
|
@ -720,7 +732,7 @@ do_measure(
|
|||
txfree(an_type); txfree(resname); txfree(meastype);
|
||||
|
||||
// see if number of measurements exceeds fixed array size of 20,000
|
||||
if ( mindex >= 20000 ) {
|
||||
if ( idx >= 20000 ) {
|
||||
fprintf( stderr, "ERROR: number of measurements exceeds 20,000!\nAborting...\n" );
|
||||
#ifdef HAS_WINDOWS
|
||||
winmessage("Fatal error in SPICE");
|
||||
|
|
@ -817,3 +829,44 @@ check_autostop( char* what ) {
|
|||
|
||||
return flag;
|
||||
}
|
||||
|
||||
static wordlist *measure_parse_line( char *line )
|
||||
{
|
||||
int len ; /* length of string */
|
||||
wordlist *wl ; /* build a word list - head of list */
|
||||
wordlist *new_item ; /* single item of a list */
|
||||
char *item ; /* parsed item */
|
||||
char *long_str ; /* concatenated string */
|
||||
char *extra_item ; /* extra item */
|
||||
|
||||
wl = NULL ;
|
||||
(void) gettok(&line) ;
|
||||
do {
|
||||
item = gettok(&line) ;
|
||||
if(!(item)){
|
||||
break ;
|
||||
}
|
||||
len = strlen(item) ;
|
||||
if( item[len-1] == '=' ){
|
||||
/* We can't end on an equal append the next piece */
|
||||
extra_item = gettok(&line) ;
|
||||
if(!(extra_item)){
|
||||
break ;
|
||||
}
|
||||
len += strlen( extra_item ) + 2 ;
|
||||
long_str = MALLOC(len) ;
|
||||
sprintf( long_str, "%s%s", item, extra_item ) ;
|
||||
txfree( item ) ;
|
||||
txfree( extra_item ) ;
|
||||
item = long_str ;
|
||||
}
|
||||
new_item = alloc(struct wordlist) ;
|
||||
new_item->wl_word = item ;
|
||||
new_item->wl_next = NULL ;
|
||||
new_item->wl_prev = NULL ;
|
||||
wl = wl_append(wl, new_item) ;
|
||||
} while( line && *line ) ;
|
||||
|
||||
return(wl) ;
|
||||
|
||||
} /* end measure_parse_line() */
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@
|
|||
#include "numparam.h"
|
||||
#include "ngspice.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
/* random numbers in /maths/misc/randnumb.c */
|
||||
extern double gauss();
|
||||
|
||||
|
|
@ -1724,8 +1728,13 @@ nupa_substitute (tdico * dico, char *s, char *r, unsigned char err)
|
|||
else
|
||||
{
|
||||
pscopy (t, s, i + 1, k - i - 1);
|
||||
err = evaluate (dico, q, t, 0);
|
||||
}
|
||||
/* exeption made for .meas */
|
||||
if( strcasecmp(t,"LAST")==0) {
|
||||
strcpy(q,"last") ;
|
||||
err=0;
|
||||
} else
|
||||
err = evaluate (dico, q, t, 0);
|
||||
}
|
||||
|
||||
i = k;
|
||||
if (!err)
|
||||
|
|
|
|||
|
|
@ -767,6 +767,10 @@
|
|||
RelativePath="..\src\frontend\com_let.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\frontend\com_measure2.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\frontend\com_option.h"
|
||||
>
|
||||
|
|
@ -1208,11 +1212,11 @@
|
|||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\spicelib\parser\inp.h"
|
||||
RelativePath="..\src\frontend\inp.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\frontend\inp.h"
|
||||
RelativePath="..\src\spicelib\parser\inp.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
|
@ -4447,6 +4451,10 @@
|
|||
RelativePath="..\src\frontend\com_let.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\frontend\com_measure2.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\frontend\com_option.c"
|
||||
>
|
||||
|
|
|
|||
Loading…
Reference in New Issue