diff --git a/ChangeLog b/ChangeLog index 50a81605a..258d47c2d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2009-08-23 Holger Vogt +2009-08-29 Holger Vogt * measure.c, com-measure2.c, com-measure2.h: add DC and AC measurement * /examples/measure: example file for .measure dc, ac, and tran added. diff --git a/examples/measure/rc-meas-ac.sp b/examples/measure/rc-meas-ac.sp index 975e60539..2d464ba58 100644 --- a/examples/measure/rc-meas-ac.sp +++ b/examples/measure/rc-meas-ac.sp @@ -25,6 +25,11 @@ R2 out gnd 1k .ac DEC 10 1k 10MEG .meas ac vout_at FIND v(out) AT=1MEG +.meas ac vout_atr FIND vr(out) AT=1MEG +.meas ac vout_ati FIND vi(out) AT=1MEG +.meas ac vout_atm FIND vm(out) AT=1MEG +.meas ac vout_atp FIND vp(out) AT=1MEG +.meas ac vout_atd FIND vdb(out) AT=1MEG .meas ac vout_max max v(out) from=1k to=10MEG .meas ac freq_at when v(out)=0.1 .meas ac vout_diff trig v(out) val=0.1 rise=1 targ v(out) val=0.1 fall=1 @@ -40,6 +45,9 @@ R2 out gnd 1k run *rusage all plot v(out) +plot ph(v(out)) +plot mag(v(out)) +plot db(v(out)) .endc .end diff --git a/src/frontend/com_measure2.c b/src/frontend/com_measure2.c index 6afe27f2b..73dfb19e3 100644 --- a/src/frontend/com_measure2.c +++ b/src/frontend/com_measure2.c @@ -31,7 +31,9 @@ typedef struct measure char *m_vec; // name of the output variable which determines the beginning of the measurement char *m_vec2; // second output variable to measure if applicable - char *m_analysis; // analysis type (tran, dc or ac) + char *m_analysis; // analysis type (tran, dc or ac) + char m_vectype; // type of vector m_vec (vm, vi, vr, vp, vdb) + char m_vectype2; // type of vector m_vec2 (vm, vi, vr, vp, vdb) int m_rise; // count number of rise events int m_fall; // count number of fall events int m_cross; // count number of rise/fall aka cross events @@ -78,24 +80,91 @@ static void measure_errMessage(char *mName, char *mFunction, char *trigTarg, cha return; } /* end measure_errMessage() */ + +/* If you have a vector vm(out), extract 'm' to meas->m_vectype + and v(out) to meas->m_vec */ + +static +void correct_vec(MEASUREPTR meas) +{ + char *vec, *vecfirst, newvec[BSIZE_SP]; + char *vec2, newvec2[BSIZE_SP]; + + vec = meas->m_vec; + + if (*(++vec) != '(') { + vecfirst = copy(meas->m_vec); + vecfirst[1] = '\0'; + meas->m_vectype = *vec; + sprintf(newvec, "%s%s", vecfirst, strstr(meas->m_vec, "(")); + tfree(meas->m_vec); + tfree(vecfirst); + meas->m_vec = copy(newvec); + } + + vec2 = meas->m_vec2; + if (vec2 && (*(++vec2) != '(')) { + vecfirst = copy(meas->m_vec); + vecfirst[1] = '\0'; + meas->m_vectype2 = *vec2; + sprintf(newvec, "%s%s", vecfirst, strstr(meas->m_vec2, "(")); + tfree(meas->m_vec2); + tfree(vecfirst); + meas->m_vec2 = copy(newvec2); + } + return; +}; + +static double get_value(MEASUREPTR meas, struct dvec *values, int idx) +{ + double ar, bi, tt; + + ar = values->v_compdata[idx].cx_real; + bi = values->v_compdata[idx].cx_imag; + + if ((meas->m_vectype == 'm') || (meas->m_vectype == 'M')) + { + return sqrt(ar*ar + bi*bi); + } + else if ((meas->m_vectype == 'r') || (meas->m_vectype == 'R')) + { + return ar; + } + else if ((meas->m_vectype == 'i') || (meas->m_vectype == 'I')) + { + return bi; + } + else if ((meas->m_vectype == 'p') || (meas->m_vectype == 'P')) + { + return radtodeg(atan2(bi, ar)); + } + else if ((meas->m_vectype == 'd') || (meas->m_vectype == 'D')) + { + tt = sqrt(ar*ar + bi*bi); + return 20.0 * log10(tt); + } + else + return ar; +} + +/* interpolate. If ac simulation, exploit vector type using complex data for y */ static double -measure_interpolate( struct dvec *xScale, struct dvec *values, int i, int j, double var_value, char x_or_y , char* analysis) +measure_interpolate( struct dvec *xScale, struct dvec *values, int i, int j, double var_value, + char x_or_y , MEASUREPTR meas) { double slope; double yint; double result; - if (cieq (analysis,"ac")) { - slope = (values->v_compdata[j].cx_real - values->v_compdata[i].cx_real) / - (xScale->v_compdata[j].cx_real - xScale->v_compdata[i].cx_real); - - yint = values->v_compdata[i].cx_real - slope*xScale->v_compdata[i].cx_real; + if (cieq (meas->m_analysis,"ac")) { + slope = (get_value(meas, values, j) - get_value(meas, values, i)) / + (xScale->v_compdata[j].cx_real - xScale->v_compdata[i].cx_real); + yint = get_value(meas, values, i) - slope*xScale->v_compdata[i].cx_real; } else { - slope = (values->v_realdata[j] - values->v_realdata[i]) / - (xScale->v_realdata[j] - xScale->v_realdata[i]); - - yint = values->v_realdata[i] - slope*xScale->v_realdata[i]; + slope = (values->v_realdata[j] - values->v_realdata[i]) / + (xScale->v_realdata[j] - xScale->v_realdata[i]); + yint = values->v_realdata[i] - slope*xScale->v_realdata[i]; } if ( x_or_y == 'x' ) result = (var_value - yint)/slope; @@ -104,6 +173,7 @@ measure_interpolate( struct dvec *xScale, struct dvec *values, int i, int j, dou return result; } /* end measure_interpolate() */ + /* ----------------------------------------------------------------- * Function: Given an operation string returns back the measure type - one of * the enumerated type ANALSYS_TYPE_T. @@ -299,7 +369,7 @@ static void com_measure_when( // timeValue = dTime->v_realdata[i]; if (cieq (meas->m_analysis,"ac")) { - value = d->v_compdata[i].cx_real; + value = get_value(meas, d, i); //d->v_compdata[i].cx_real; timeValue = dTime->v_compdata[i].cx_real; } else { @@ -414,7 +484,7 @@ static void measure_at( for (i=0; i < d->v_length; i++) { if (cieq (meas->m_analysis,"ac")) { - value = d->v_compdata[i].cx_real; + value = get_value(meas, d, i); //d->v_compdata[i].cx_real; svalue = dScale->v_compdata[i].cx_real; } else { @@ -483,7 +553,7 @@ static void measure_minMaxAvg( for (i=0; i < d->v_length; i++) { if (cieq (meas->m_analysis,"ac")) { - value = d->v_compdata[i].cx_real; + value = get_value(meas, d, i); //d->v_compdata[i].cx_real; svalue = dScale->v_compdata[i].cx_real; } else { @@ -610,7 +680,7 @@ static void measure_rms_integral( // create new set of values over interval [from, to] -- interpolate if necessary for (i=0; i < d->v_length; i++) { if (cieq (meas->m_analysis,"ac")) { - value = d->v_compdata[i].cx_real; + value = get_value(meas, d, i); //d->v_compdata[i].cx_real; xvalue = xScale->v_compdata[i].cx_real; } else { @@ -624,7 +694,7 @@ static void measure_rms_integral( if ((meas->m_to != 0.0e0) && (xvalue > meas->m_to) ){ // interpolate ending value if necessary. if (!(AlmostEqualUlps( xvalue, meas->m_to, 100))){ - value = measure_interpolate( xScale, d, i-1, i, meas->m_to, 'y', meas->m_analysis ); + value = measure_interpolate( xScale, d, i-1, i, meas->m_to, 'y', meas ); xvalue = meas->m_to ; } x[xy_size] = xvalue ; @@ -640,7 +710,7 @@ static void measure_rms_integral( if( meas->m_from != 0.0e0 && (i > 0) ){ // interpolate starting value. if (!(AlmostEqualUlps( xvalue, meas->m_from, 100))){ - value = measure_interpolate( xScale, d, i-1, i, meas->m_from, 'y' , meas->m_analysis); + value = measure_interpolate( xScale, d, i-1, i, meas->m_from, 'y' , meas); xvalue = meas->m_from ; } } @@ -684,7 +754,7 @@ static void measure_rms_integral( /* Now set the measurement values if not set */ if( toVal < 0.0 ){ if (cieq (meas->m_analysis,"ac")) { - value = d->v_compdata[i].cx_real; + value = get_value(meas, d, i); //d->v_compdata[i].cx_real; xvalue = xScale->v_compdata[i].cx_real; toVal = xScale->v_compdata[d->v_length-1].cx_real; } @@ -918,6 +988,9 @@ static int measure_parse_find ( if (pCnt == 0 ) { meas->m_vec= cp_unquote(wl->wl_word); + /* correct for vectors like vm, vp etc. */ + if (cieq("ac", meas->m_analysis)) + correct_vec(meas); } else if (pCnt == 1) { pName = strtok(p, "="); @@ -993,9 +1066,14 @@ static int measure_parse_when ( return 0; } - meas->m_vec = pVar1; - if (measure_valid_vector(pVar2)==1) - meas->m_vec2 = pVar2; + meas->m_vec = copy(pVar1); + /* correct for vectors like vm, vp etc. */ + if (cieq("ac", meas->m_analysis)) correct_vec(meas); + if (measure_valid_vector(pVar2)==1) { + meas->m_vec2 = copy(pVar2); + /* correct for vectors like vm, vp etc. */ + if (cieq("ac", meas->m_analysis)) correct_vec(meas); + } else meas->m_val = atof(pVar2); } else { @@ -1043,6 +1121,9 @@ static int measure_parse_trigtarg ( if ((pcnt == 0) && !ciprefix("at", p)) { meas->m_vec= cp_unquote(words->wl_word); + /* correct for vectors like vm, vp etc. */ + if (cieq("ac", meas->m_analysis)) + correct_vec(meas); } else if (ciprefix("at", p)) { if (measure_parse_stdParams(meas, words, wlTarg, errbuf) == 0) return 0; @@ -1111,7 +1192,7 @@ get_measure2( if (!ciprefix("tran", plot_cur->pl_typename) && !ciprefix("ac", plot_cur->pl_typename) && !ciprefix("dc", plot_cur->pl_typename)) { - fprintf(cp_err, "Error: measure limited to tran or ac analysis\n"); + fprintf(cp_err, "Error: measure limited to tran, dc or ac analysis\n"); return MEASUREMENT_FAILURE; } @@ -1319,13 +1400,13 @@ get_measure2( { MEASUREPTR meas; meas = (struct measure*)tmalloc(sizeof(struct measure)); - + meas->m_analysis = mAnalysis; if (measure_parse_when(meas, words, errbuf) ==0) { measure_errMessage(mName, mFunction, "WHEN", errbuf, autocheck); return MEASUREMENT_FAILURE; } - meas->m_analysis = mAnalysis; + com_measure_when(meas); @@ -1351,12 +1432,12 @@ get_measure2( // trig parameters MEASUREPTR meas; meas = (struct measure*)tmalloc(sizeof(struct measure)); - + meas->m_analysis = mAnalysis; if (measure_parse_trigtarg(meas, words , NULL, "trig", errbuf)==0) { measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck); return MEASUREMENT_FAILURE; } - meas->m_analysis = mAnalysis; + // measure measure_rms_integral(meas,mFunctionType); @@ -1385,13 +1466,13 @@ get_measure2( MEASUREPTR meas; meas = (struct measure*)tmalloc(sizeof(struct measure)); + meas->m_analysis = mAnalysis; + if (measure_parse_trigtarg(meas, words , NULL, "trig", errbuf)==0) { measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck); return MEASUREMENT_FAILURE; } - meas->m_analysis = mAnalysis; - // measure measure_minMaxAvg(meas, mFunctionType); @@ -1455,12 +1536,12 @@ get_measure2( MEASUREPTR measTrig; measTrig = (struct measure*)tmalloc(sizeof(struct measure)); - + measTrig->m_analysis = mAnalysis; if (measure_parse_trigtarg(measTrig, words , NULL, "trig", errbuf)==0) { measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck); return MEASUREMENT_FAILURE; } - measTrig->m_analysis = mAnalysis; + // measure min measure_minMaxAvg(measTrig, AT_MIN); if (measTrig->m_measured == 0.0e0) { diff --git a/src/frontend/dotcards.c b/src/frontend/dotcards.c index a2d2da260..d9e7e10b2 100644 --- a/src/frontend/dotcards.c +++ b/src/frontend/dotcards.c @@ -137,7 +137,7 @@ ft_savedotargs(void) some = 1; com_save2(w, "TRAN"); /* A hack */ } - } else if (ciprefix(".measure", s)) { + } else if (ciprefix(".meas", s)) { status = measure_extract_variables( s ) ; if(!(status)){ some = 1;