optimized usage of interpolate_yval(), add raw->cursor_b_val[]

This commit is contained in:
stefan schippers 2023-10-16 09:53:03 +02:00
parent d1309a8a47
commit f10555917e
8 changed files with 98 additions and 87 deletions

View File

@ -514,6 +514,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
<li><kbd> abort_operation</kbd></li><pre>
@ -1030,13 +1031,14 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
xschem raw_query datasets: get number of datasets (simulation runs)
xschem raw_query value node n: return n-th value of 'node' in raw file
xschem raw_query loaded: return hierarchy level
xschem raw_query filename: return raw filename
where raw file was loaded or -1 if no raw loaded
xschem raw_query index node: get index of simulation variable 'node'.
Example: raw_query index v(led) --&gt; 46
xschem raw_query values node [dset] : print all simulation
values of 'node' for dataset 'dset' (default dset=0)
xschem raw_query points [dset] : print simulation points for
dataset 'dset' (default dataset points combined)</pre>
dataset 'dset' (default: all dataset points combined)</pre>
<li><kbd> raw_read [file] [sim]</kbd></li><pre>
If a raw file is already loaded delete from memory
else load specified file and analysis 'sim' (dc, ac, tran, op, ...)
@ -1281,7 +1283,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
props is the attribute string
size sets the size
draw is a flag. If set to 1 will draw the created text </pre>
<li><kbd> test </kbd></li><pre>
<li><kbd> test [rawfile type]</kbd></li><pre>
testmode </pre>
<li><kbd> toggle_colorscheme</kbd></li><pre>
Toggle dark/light colorscheme </pre>
@ -1379,7 +1381,6 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
</ul>

View File

@ -188,11 +188,30 @@ static void start_wire(double mx, double my)
}
static double interpolate_yval(int idx, int point_not_last)
{
double val = xctx->raw->values[idx][xctx->raw->annot_p];
/* not operating point, annotate from 'b' cursor */
if((xctx->raw->allpoints > 1) && xctx->raw->annot_sweep_idx >= 0) {
Raw *raw = xctx->raw;
SPICE_DATA *sweep_gv = raw->values[raw->annot_sweep_idx];
SPICE_DATA *gv = raw->values[idx];
if(point_not_last) {
double dx = sweep_gv[raw->annot_p + 1] - sweep_gv[raw->annot_p];
double dy = gv[raw->annot_p + 1] - gv[raw->annot_p];
double offset = raw->annot_x - sweep_gv[raw->annot_p];
double interp = dx != 0.0 ? offset * dy / dx : 0.0;
val += interp;
}
}
return val;
}
static void backannotate_at_cursor_b_pos(xRect *r, Graph_ctx *gr)
{
if(sch_waves_loaded() >= 0) {
int dset, first = -1, last, dataset = gr->dataset, i, p, ofs = 0;
int dset, first = -1, last, dataset = gr->dataset, i, p, ofs = 0, ofs_end;
double start, end;
int sweepvar_wrap = 0, sweep_idx;
double xx, cursor2; /* xx is the p-th sweep variable value, cursor2 is cursor 'b' x position */
@ -217,10 +236,11 @@ static void backannotate_at_cursor_b_pos(xRect *r, Graph_ctx *gr)
int cnt=0, wrap;
register SPICE_DATA *gv = raw->values[sweep_idx];
int s=0;
ofs_end = ofs + raw->npoints[dset];
first = -1;
prev_prev_x = prev_x = 0;
last = ofs;
for(p = ofs ; p < ofs + raw->npoints[dset]; p++) {
for(p = ofs ; p < ofs_end; p++) {
xx = gv[p];
wrap = ( cnt > 1 && XSIGN(xx - prev_x) != XSIGN(prev_x - prev_prev_x));
if(wrap) {
@ -233,13 +253,13 @@ static void backannotate_at_cursor_b_pos(xRect *r, Graph_ctx *gr)
xx, cursor2, first, last, start, end, p, wrap, sweepvar_wrap, ofs);
if(first == -1) first = p;
if(p == first) {
if(xx == cursor2) {dset = raw->datasets; break;}
if(xx == cursor2) {goto done;}
s = XSIGN0(xx - cursor2);
dbg(1, "s=%d\n", s);
} else {
int ss = XSIGN0(xx - cursor2);
dbg(1, "s=%d, ss=%d\n", s, ss);
if(ss != s) {dset = raw->datasets; break;}
if(ss != s) {goto done;}
}
last = p;
}
@ -249,10 +269,10 @@ static void backannotate_at_cursor_b_pos(xRect *r, Graph_ctx *gr)
prev_x = xx;
} /* for(p = ofs ; p < ofs + raw->npoints[dset]; p++) */
/* offset pointing to next dataset */
ofs += raw->npoints[dset];
ofs = ofs_end;
sweepvar_wrap++;
} /* for(dset...) */
done:
if(first != -1) {
if(p > last) {
double sweep0, sweep1;
@ -264,18 +284,19 @@ static void backannotate_at_cursor_b_pos(xRect *r, Graph_ctx *gr)
}
}
dbg(1, "xx=%g, p=%d\n", xx, p);
tcleval("array unset ngspice::ngspice_data");
Tcl_UnsetVar(interp, "ngspice::ngspice_data", TCL_GLOBAL_ONLY);
raw->annot_p = p;
raw->annot_x = cursor2;
raw->annot_sweep_idx = sweep_idx;
for(i = 0; i < raw->nvars; ++i) {
char s[100];
my_snprintf(s, S(s), "%.4g", raw->values[i][p]);
dbg(1, "%s = %g\n", raw->names[i], raw->values[i][p]);
tclvareval("array set ngspice::ngspice_data [list {", raw->names[i], "} ", s, "]", NULL);
raw->cursor_b_val[i] = interpolate_yval(i, (p < ofs_end));
my_snprintf(s, S(s), "%.5g", raw->cursor_b_val[i]);
/* tclvareval("array set ngspice::ngspice_data [list {", raw->names[i], "} ", s, "]", NULL); */
Tcl_SetVar2(interp, "ngspice::ngspice_data", raw->names[i], s, TCL_GLOBAL_ONLY);
}
tclvareval("set ngspice::ngspice_data(n\\ vars) ", my_itoa( raw->nvars), NULL);
tclvareval("set ngspice::ngspice_data(n\\ points) 1", NULL);
Tcl_SetVar2(interp, "ngspice::ngspice_data", "n\\ vars", my_itoa( raw->nvars), TCL_GLOBAL_ONLY);
Tcl_SetVar2(interp, "ngspice::ngspice_data", "n\\ points", "1", TCL_GLOBAL_ONLY);
}
}
}

View File

@ -2083,12 +2083,13 @@ int graph_fullyzoom(xRect *r, Graph_ctx *gr, int dataset)
}
if(xctx->raw && v >= 0) {
int sweepvar_wrap = 0; /* incremented on new dataset or sweep variable wrap */
int ofs = 0;
int ofs = 0, ofs_end;
for(dset = 0 ; dset < raw->datasets; dset++) {
double xx, xx0;
int cnt=0, wrap;
register SPICE_DATA *gv = raw->values[sweep_idx];
for(p = ofs ; p < ofs + raw->npoints[dset]; p++) {
ofs_end = ofs + raw->npoints[dset];
for(p = ofs ; p < ofs_end; p++) {
if(gr->logx) xx = mylog10(gv[p]);
else xx = gv[p];
if(p == ofs) xx0 = xx;
@ -2114,7 +2115,7 @@ int graph_fullyzoom(xRect *r, Graph_ctx *gr, int dataset)
}
} /* for(p = ofs ; p < ofs + raw->npoints[dset]; p++) */
/* offset pointing to next dataset */
ofs += raw->npoints[dset];
ofs = ofs_end;
sweepvar_wrap++;
} /* for(dset...) */
}
@ -2911,7 +2912,7 @@ int edit_wave_attributes(int what, int i, Graph_ctx *gr)
int calc_custom_data_yrange(int sweep_idx, const char *express, Graph_ctx *gr)
{
int idx = -1;
int p, dset, ofs;
int p, dset, ofs, ofs_end;
int first, last;
double xx; /* the p-th sweep variable value: xctx->raw->values[sweep_idx][p] */
double xx0 = 0; /* first sweep value */
@ -2930,9 +2931,10 @@ int calc_custom_data_yrange(int sweep_idx, const char *express, Graph_ctx *gr)
for(dset = 0 ; dset < raw->datasets; dset++) {
int cnt=0, wrap;
register SPICE_DATA *gv = raw->values[sweep_idx];
ofs_end = ofs + raw->npoints[dset];
first = -1;
last = ofs;
for(p = ofs ; p < ofs + raw->npoints[dset]; p++) {
for(p = ofs ; p < ofs_end; p++) {
if(gr->logx)
xx = mylog10(gv[p]);
else
@ -2965,7 +2967,7 @@ int calc_custom_data_yrange(int sweep_idx, const char *express, Graph_ctx *gr)
}
}
/* offset pointing to next dataset */
ofs += raw->npoints[dset];
ofs = ofs_end;
sweepvar_wrap++;
} /* for(dset...) */
return idx;
@ -3028,7 +3030,7 @@ int find_closest_wave(int i, Graph_ctx *gr)
else idx = get_raw_index(express);
dbg(1, "find_closest_wave(): expression=%d, idx=%d\n", expression, idx);
if( idx != -1 ) {
int p, dset, ofs;
int p, dset, ofs, ofs_end;
int first, last;
double xx, yy ; /* the p-th point */
double xx0 = 0.0; /* first sweep value */
@ -3044,7 +3046,8 @@ int find_closest_wave(int i, Graph_ctx *gr)
int cnt=0, wrap;
register SPICE_DATA *gvx = raw->values[sweep_idx];
register SPICE_DATA *gvy;
if(expression) plot_raw_custom_data(sweep_idx, ofs, ofs + raw->npoints[dset]-1, express);
ofs_end = ofs + raw->npoints[dset];
if(expression) plot_raw_custom_data(sweep_idx, ofs, ofs_end - 1, express);
gvy = raw->values[idx];
dbg(1, "find_closest_wave(): dset=%d\n", dset);
first = -1;
@ -3052,7 +3055,7 @@ int find_closest_wave(int i, Graph_ctx *gr)
* p loop split repeated 2 timed (for x and y points) to preserve cache locality */
last = ofs;
dbg(1, "find_closest_wave(): xval=%g yval=%g\n", xval, yval);
for(p = ofs ; p < ofs + raw->npoints[dset]; p++) {
for(p = ofs ; p < ofs_end; p++) {
if(gr->logx) xx = mylog10(gvx[p]);
else xx = gvx[p];
if(p == ofs) xx0 = xx;
@ -3092,7 +3095,7 @@ int find_closest_wave(int i, Graph_ctx *gr)
prev_x = xx;
} /* for(p = ofs ; p < ofs + raw->npoints[dset]; p++) */
/* offset pointing to next dataset */
ofs += raw->npoints[dset];
ofs = ofs_end;
sweepvar_wrap++;
} /* for(dset...) */
@ -3224,7 +3227,7 @@ void draw_graph(int i, const int flags, Graph_ctx *gr, void *ct)
}
/* quickly find index number of ntok_copy variable to be plotted */
if( expression || (idx = get_raw_index(bus_msb ? bus_msb : express)) != -1 ) {
int p, dset, ofs;
int p, dset, ofs, ofs_end;
int poly_npoints;
int first, last;
double xx; /* the p-th sweep variable value: raw->values[sweep_idx][p] */
@ -3251,7 +3254,8 @@ void draw_graph(int i, const int flags, Graph_ctx *gr, void *ct)
double prev_x;
int cnt=0, wrap;
register SPICE_DATA *gv = raw->values[sweep_idx];
ofs_end = ofs + raw->npoints[dset];
first = -1;
poly_npoints = 0;
my_realloc(_ALLOC_ID_, &point, raw->npoints[dset] * sizeof(XPoint));
@ -3259,7 +3263,7 @@ void draw_graph(int i, const int flags, Graph_ctx *gr, void *ct)
* p loop split repeated 2 timed (for x and y points) to preserve cache locality */
prev_x = 0;
last = ofs;
for(p = ofs ; p < ofs + raw->npoints[dset]; p++) {
for(p = ofs ; p < ofs_end; p++) {
if(gr->logx) xx = mylog10(gv[p]);
else xx = gv[p];
if(p == ofs) xx0 = xx;
@ -3326,7 +3330,7 @@ void draw_graph(int i, const int flags, Graph_ctx *gr, void *ct)
}
}
/* offset pointing to next dataset */
ofs += raw->npoints[dset];
ofs = ofs_end;
sweepvar_wrap++;
} /* for(dset...) */
bbox(END, 0.0, 0.0, 0.0, 0.0);

View File

@ -610,6 +610,7 @@ static int read_dataset(FILE *fd, Raw **rawptr, const char *type)
char *ptr;
/* get the list of lines with index and node name */
if(!raw->names) raw->names = my_calloc(_ALLOC_ID_, raw->nvars, sizeof(char *));
if(!raw->cursor_b_val) raw->cursor_b_val = my_calloc(_ALLOC_ID_, raw->nvars, sizeof(double));
my_realloc(_ALLOC_ID_, &varname, strlen(line) + 1) ;
n = sscanf(line, "%d %s", &i, varname); /* read index and name of saved waveform */
if(n < 2) {
@ -672,6 +673,7 @@ void free_rawfile(Raw **rawptr, int dr)
my_free(_ALLOC_ID_, &raw->names[i]);
}
my_free(_ALLOC_ID_, &raw->names);
my_free(_ALLOC_ID_, &raw->cursor_b_val);
}
if(raw->values) {
deleted = 1;
@ -682,8 +684,8 @@ void free_rawfile(Raw **rawptr, int dr)
my_free(_ALLOC_ID_, &raw->values);
}
if(raw->npoints) my_free(_ALLOC_ID_, &raw->npoints);
if(raw->filename) my_free(_ALLOC_ID_, &raw->filename);
if(raw->schname) my_free(_ALLOC_ID_, &raw->schname);
my_strncpy(raw->filename, "", S(raw->filename));
if(raw->table.table) int_hash_free(&raw->table);
my_free(_ALLOC_ID_, rawptr);
if(deleted && dr) draw();
@ -780,7 +782,7 @@ int raw_read(const char *f, Raw **rawptr, const char *type)
if(fd) {
if((res = read_dataset(fd, rawptr, type)) == 1) {
int i;
my_strncpy(raw->filename, f, S(raw->filename));
my_strdup2(_ALLOC_ID_, &raw->filename, f);
my_strdup2(_ALLOC_ID_, &raw->schname, xctx->sch[xctx->currsch]);
raw->level = xctx->currsch;
raw->allpoints = 0;
@ -925,8 +927,8 @@ int table_read(const char *f)
raw->allpoints = 0;
if(res == 1) {
int i;
my_strdup2(_ALLOC_ID_, &raw->filename, f);
my_strdup2(_ALLOC_ID_, &raw->schname, xctx->sch[xctx->currsch]);
my_strncpy(raw->filename, f, S(raw->filename));
raw->level = xctx->currsch;
raw->allpoints = 0;
for(i = 0; i < raw->datasets; ++i) {
@ -938,7 +940,7 @@ int table_read(const char *f)
} else {
dbg(0, "table_read(): no useful data found\n");
}
raw->cursor_b_val = my_calloc(_ALLOC_ID_, raw->nvars, sizeof(double));
fclose(fd);
return res;
}

View File

@ -3087,13 +3087,14 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
* xschem raw_query datasets: get number of datasets (simulation runs)
* xschem raw_query value node n: return n-th value of 'node' in raw file
* xschem raw_query loaded: return hierarchy level
* xschem raw_query filename: return raw filename
* where raw file was loaded or -1 if no raw loaded
* xschem raw_query index node: get index of simulation variable 'node'.
* Example: raw_query index v(led) --> 46
* xschem raw_query values node [dset] : print all simulation
* values of 'node' for dataset 'dset' (default dset=0)
* xschem raw_query points [dset] : print simulation points for
* dataset 'dset' (default dataset points combined)
* dataset 'dset' (default: all dataset points combined)
*/
else if(!strcmp(argv[1], "raw_query"))
{
@ -3156,6 +3157,8 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
if(dset >= 0 && dset < raw->datasets)
Tcl_SetResult(interp, my_itoa(raw->npoints[dset]), TCL_VOLATILE);
}
} else if(argc > 2 && !strcmp(argv[2], "filename")) {
Tcl_SetResult(interp, raw->filename, TCL_VOLATILE);
} else if(argc > 2 && !strcmp(argv[2], "vars")) {
Tcl_SetResult(interp, my_itoa(raw->nvars), TCL_VOLATILE);
} else if(argc > 2 && !strcmp(argv[2], "list")) {
@ -4524,26 +4527,30 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
}
/* test
/* test [rawfile type]
* testmode */
else if(0 && !strcmp(argv[1], "test"))
else if(!strcmp(argv[1], "test"))
{
static int swap = 0;
static Raw *saveraw = NULL;
if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
if(swap == 0) {
saveraw = xctx->raw;
swap = 1;
xctx->raw = NULL;
raw_read("/home/schippes/.xschem/simulations/cmos_example_ngspice2.raw", &xctx->raw, "dc");
draw();
} else {
free_rawfile(&xctx->raw, 0);
swap = 0;
xctx->raw = saveraw;
draw();
}
static int cnt = 1;
static Raw *raw[10];
static int nraw = 0;
if(nraw == 0) {
raw[nraw] = xctx->raw;
nraw++;
}
if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
if(argc > 3) {
xctx->raw = NULL;
raw_read(argv[2], &xctx->raw, argv[3]);
raw[nraw] = xctx->raw;
nraw++;
cnt = (cnt + 1) % nraw;
draw();
} else {
xctx->raw = raw[cnt];
cnt = (cnt + 1) % nraw;
}
Tcl_ResetResult(interp);
}

View File

@ -3380,31 +3380,6 @@ static char *get_pin_attr(const char *token, int inst, int s_pnetname)
return value;
}
static double interpolate_yval(int idx)
{
double val = xctx->raw->values[idx][xctx->raw->annot_p];
/* not operating point, annotate from 'b' cursor */
if((xctx->raw->allpoints > 1) && xctx->raw->annot_sweep_idx >= 0) {
Raw *raw = xctx->raw;
int dset;
int npoints = 0;
SPICE_DATA *sweep_gv = raw->values[raw->annot_sweep_idx];
SPICE_DATA *gv = raw->values[idx];
for(dset = 0 ; dset < raw->datasets; dset++) {
npoints += raw->npoints[dset];
if(npoints > raw->annot_p) break;
}
if(raw->annot_p + 1 < npoints) {
double dx = sweep_gv[raw->annot_p + 1] - sweep_gv[raw->annot_p];
double dy = gv[raw->annot_p + 1] - gv[raw->annot_p];
double offset = raw->annot_x - sweep_gv[raw->annot_p];
double interp = dx != 0.0 ? offset * dy / dx : 0.0;
val += interp;
}
}
return val;
}
/* substitute given tokens in a string with their corresponding values */
/* ex.: name=@name w=@w l=@l ---> name=m112 w=3e-6 l=0.8e-6 */
/* if s==NULL return emty string */
@ -3624,7 +3599,7 @@ const char *translate(int inst, const char* s)
dbg(1, "translate() @spice_get_voltage: fqnet=%s start_level=%d\n", fqnet, start_level);
idx = get_raw_index(fqnet);
if(idx >= 0) {
val = interpolate_yval(idx);
val = xctx->raw->cursor_b_val[idx];
}
if(idx < 0) {
valstr = "";
@ -3681,7 +3656,7 @@ const char *translate(int inst, const char* s)
dbg(1, "translate(): net=%s, fqnet=%s start_level=%d\n", net, fqnet, start_level);
idx = get_raw_index(fqnet);
if(idx >= 0) {
val = interpolate_yval(idx);
val = xctx->raw->cursor_b_val[idx];
}
if(idx < 0) {
valstr = "";
@ -3749,7 +3724,7 @@ const char *translate(int inst, const char* s)
dbg(1, "fqdev=%s\n", fqdev);
idx = get_raw_index(fqdev);
if(idx >= 0) {
val = interpolate_yval(idx);
val = xctx->raw->cursor_b_val[idx];
}
if(idx < 0) {
valstr = "";
@ -3815,7 +3790,7 @@ const char *translate(int inst, const char* s)
xctx->tok_size = 0;
len = 0;
} else {
val = interpolate_yval(idx1) - interpolate_yval(idx2);
val = xctx->raw->cursor_b_val[idx1] - xctx->raw->cursor_b_val[idx2];
valstr = dtoa_eng(val);
len = xctx->tok_size;
}
@ -3875,7 +3850,7 @@ const char *translate(int inst, const char* s)
strtolower(fqdev);
idx = get_raw_index(fqdev);
if(idx >= 0) {
val = interpolate_yval(idx);
val = xctx->raw->cursor_b_val[idx];
}
if(idx < 0) {
valstr = "";

View File

@ -766,7 +766,7 @@ struct hilight_hashentry
typedef struct {
/* spice raw file specific data */
char **names;
char filename[PATH_MAX];
char *filename;
SPICE_DATA **values;
int nvars;
int *npoints;
@ -780,6 +780,7 @@ typedef struct {
double annot_x; /* X point to backannotate as calculated from mouse position.
* need to interpolate the Y value between annot_p and annot_p + 1 */
int annot_sweep_idx; /* index of sweep variable where cursor annotation has occurred */
double *cursor_b_val;
/* when descending hierarchy xctx->current_name changes, xctx->raw_schname
* holds the name of the top schematic from which the raw file was loaded */
char *schname;

View File

@ -51,7 +51,7 @@ node="cal%0
saout
saout%70
saout%3"
color="8 14 7 12"
color="8 19 7 12"
linewidth_mult=1.0
hilight_wave=-1
@ -65,8 +65,8 @@ x2=4.39927e-07
unitx=n
divx=5
subdivx=2
node="plus
minus"
node="plus%0
minus%0"
color="4 5"
dataset=-1
linewidth_mult=1.0
@ -81,8 +81,8 @@ x2=4.39927e-07
unitx=n
divx=5
subdivx=4
node="en
cal
node="en%0
cal%0
\\"SAOUT#3; vss,saout%3\\"
--slow--
\\"SAOUT#15; vss,saout%15\\"