graph axes in engineering notation (20u, 10p, 3k), fix an issue in graph panning with button1 mouse; ngspice:: get_current, get_voltage, get_diff_voltage, get_node embedded into xschem.tcl, to_eng tcl procedure to convert number to engineering form.

This commit is contained in:
Stefan Frederik 2022-09-28 19:14:31 +02:00
parent 9d9a4826fc
commit ae4b74f2d8
9 changed files with 222 additions and 191 deletions

View File

@ -314,7 +314,6 @@ static void backannotate_at_cursor_b_pos(xRect *r, Graph_ctx *gr)
static int waves_callback(int event, int mx, int my, KeySym key, int button, int aux, int state)
{
Graph_ctx *gr;
const char *val;
int i, redraw_all_at_end = 0, need_all_redraw = 0, need_redraw = 0, dataset = 0;
double xx1, xx2, yy1, yy2;
double delta_threshold = 0.25;
@ -337,6 +336,7 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int
/* check if this is the master graph (the one containing the mouse pointer) */
/* determine if mouse pointer is below xaxis or left of yaxis in some graph */
if( POINTINSIDE(xctx->mousex, xctx->mousey, r->x1, r->y1, r->x2, r->y2)) {
dbg(1, "mouse inside: %d\n", i);
setup_graph_data(i, xctx->graph_flags, 0, gr);
/* move cursor1 */
@ -354,6 +354,10 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int
}
else need_redraw = 1;
}
gr->master_gx1 = gr->gx1;
gr->master_gx2 = gr->gx2;
gr->master_gw = gr->gw;
gr->master_cx = gr->cx;
if(xctx->ui_state & GRAPHPAN) break; /* After GRAPHPAN only need to check Motion events for cursors */
if(xctx->mousey_snap < W_Y(gr->gy2)) {
xctx->graph_top = 1;
@ -437,6 +441,7 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int
break;
} /* if( POINTINSIDE(...) */
} /* for(i=0; i < xctx->rects[GRIDLAYER]; i++) */
dbg(1, "out of 1st loop: i=%d\n", i);
/* check if user clicked on a wave label -> draw wave in bold */
if(event == ButtonPress && button == Button3 &&
@ -454,17 +459,11 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int
!xctx->graph_top /* && !xctx->graph_bottom */
) {
xctx->ui_state |= GRAPHPAN;
dbg(1, "save mouse\n");
if(!xctx->graph_left) xctx->mx_double_save = xctx->mousex_snap;
if(xctx->graph_left) xctx->my_double_save = xctx->mousey_snap;
}
gr->master_gx1 = 0;
gr->master_gx2 = 1e-6;
val = get_tok_value(xctx->rect[GRIDLAYER][xctx->graph_master].prop_ptr,"x1",0);
if(val[0]) gr->master_gx1 = atof_spice(val);
val = get_tok_value(xctx->rect[GRIDLAYER][xctx->graph_master].prop_ptr,"x2",0);
if(val[0]) gr->master_gx2 = atof_spice(val);
if(gr->master_gx1 == gr->master_gx2) gr->master_gx2 += 1e-6;
gr->master_gw = gr->master_gx2 - gr->master_gx1;
dbg(1, "graph_master=%d\n", xctx->graph_master);
/* parameters for absolute positioning by mouse drag in bottom graph area */
if( event == MotionNotify && (state & Button1Mask) && xctx->graph_bottom ) {
@ -547,8 +546,8 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int
} else {
tcleval("graph_show_measure stop");
}
}
}
} /* if(xctx->graph_flags & 64) */
} /* if(i == xctx->graph_master) */
dbg(1, "%g %g %g %g - %d %d\n", gr->gx1, gr->gy1, gr->gx2, gr->gy2, gr->divx, gr->divy);
if( event == KeyPress || event == ButtonPress || event == MotionNotify ) {
/* move cursor1 */
@ -597,6 +596,7 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int
delta_threshold = 0.01;
/* selected or locked or master */
if( r->sel || !(r->flags & 2) || i == xctx->graph_master) {
dbg(1, "moving waves: %d\n", i);
if(fabs(xctx->mx_double_save - xctx->mousex_snap) > fabs(gr->cx * delta) * delta_threshold) {
xx1 = gr->gx1 + (xctx->mx_double_save - xctx->mousex_snap) / gr->cx;
xx2 = gr->gx2 + (xctx->mx_double_save - xctx->mousex_snap) / gr->cx;
@ -1024,10 +1024,12 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int
}
if(clear_graphpan_at_end) xctx->ui_state &= ~GRAPHPAN;
/* update saved mouse position after processing all graphs */
if(save_mouse_at_end &&
fabs(xctx->mx_double_save - xctx->mousex_snap) > fabs(gr->cx * gr->gw) * delta_threshold) {
xctx->mx_double_save = xctx->mousex_snap;
xctx->my_double_save = xctx->mousey_snap;
if(save_mouse_at_end) {
if( fabs(xctx->mx_double_save - xctx->mousex_snap) > fabs(gr->master_cx * gr->master_gw) * delta_threshold) {
dbg(1, "save mose pos\n");
xctx->mx_double_save = xctx->mousex_snap;
xctx->my_double_save = xctx->mousey_snap;
}
}

View File

@ -1978,10 +1978,10 @@ static void draw_graph_grid(Graph_ctx *gr, void *ct)
drawline(GRIDLAYER, ADD, W_X(wx), W_Y(gr->gy1), W_X(wx), W_Y(gr->gy1) + mark_size, 0, ct); /* axis marks */
/* X-axis labels */
if(gr->logx)
draw_string(3, NOW, dtoa(pow(10, wx) * gr->unitx), 0, 0, 1, 0, W_X(wx), gr->y2 + mark_size + 5 * gr->txtsizex,
gr->txtsizex, gr->txtsizex);
draw_string(3, NOW, dtoa_eng(pow(10, wx) * gr->unitx), 0, 0, 1, 0, W_X(wx),
gr->y2 + mark_size + 5 * gr->txtsizex, gr->txtsizex, gr->txtsizex);
else
draw_string(3, NOW, dtoa(wx * gr->unitx), 0, 0, 1, 0, W_X(wx), gr->y2 + mark_size + 5 * gr->txtsizex,
draw_string(3, NOW, dtoa_eng(wx * gr->unitx), 0, 0, 1, 0, W_X(wx), gr->y2 + mark_size + 5 * gr->txtsizex,
gr->txtsizex, gr->txtsizex);
}
/* first and last vertical box delimiters */
@ -2009,10 +2009,10 @@ static void draw_graph_grid(Graph_ctx *gr, void *ct)
drawline(GRIDLAYER, ADD, W_X(gr->gx1) - mark_size, W_Y(wy), W_X(gr->gx1), W_Y(wy), 0, ct); /* axis marks */
/* Y-axis labels */
if(gr->logy)
draw_string(3, NOW, dtoa(pow(10, wy) * gr->unity), 0, 1, 0, 1, gr->x1 - mark_size - 5 * gr->txtsizey, W_Y(wy),
gr->txtsizey, gr->txtsizey);
draw_string(3, NOW, dtoa_eng(pow(10, wy) * gr->unity), 0, 1, 0, 1,
gr->x1 - mark_size - 5 * gr->txtsizey, W_Y(wy), gr->txtsizey, gr->txtsizey);
else
draw_string(3, NOW, dtoa(wy * gr->unity), 0, 1, 0, 1, gr->x1 - mark_size - 5 * gr->txtsizey, W_Y(wy),
draw_string(3, NOW, dtoa_eng(wy * gr->unity), 0, 1, 0, 1, gr->x1 - mark_size - 5 * gr->txtsizey, W_Y(wy),
gr->txtsizey, gr->txtsizey);
}
}
@ -2036,6 +2036,7 @@ void setup_graph_data(int i, const int flags, int skip, Graph_ctx *gr)
const char *val;
xRect *r = &xctx->rect[GRIDLAYER][i];
dbg(1, "setup_graph_data: i=%d\n", i);
/* default values */
gr->divx = gr->divy = 5;
gr->subdivx = gr->subdivy = 0;

View File

@ -340,6 +340,35 @@ char *dtoa(double i)
return s;
}
char *dtoa_eng(double i)
{
static char s[70];
size_t n;
int suffix = 0;
double absi = fabs(i);
if (absi == 0.0) { suffix = 0;}
else if(absi >=1e12) { i /= 1e12; suffix = 'T';}
else if(absi >=1e9) { i /= 1e9 ; suffix = 'G';}
else if(absi >=1e6) { i /= 1e6 ; suffix = 'M';}
else if(absi >=1e3) { i /= 1e3 ; suffix = 'k';}
else if(absi >=0.1) { suffix = 0;}
else if(absi >=1e-3) { i *= 1e3 ; suffix = 'm';}
else if(absi >=1e-6) { i *= 1e6 ; suffix = 'u';}
else if(absi >=1e-9) { i *= 1e9 ; suffix = 'n';}
else if(absi >=1e-12) { i *= 1e12; suffix = 'p';}
else if(absi >=1e-15) { i *= 1e15; suffix = 'f';}
else { i *= 1e18; suffix = 'a';}
if(suffix) {
n = my_snprintf(s, S(s), "%.5g%c", i, suffix);
} else {
n = my_snprintf(s, S(s), "%.5g", i);
}
if(xctx) xctx->tok_size = n;
return s;
}
char *dtoa_prec(double i)
{
static char s[70];

View File

@ -21,12 +21,6 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
namespace eval ngspice {
# Create a variable inside the namespace
variable ngspice_data
variable op_point_read
}
proc ngspice::read_raw_dataset {arr fp} {
upvar $arr var
@ -99,141 +93,4 @@ proc ngspice::read_raw {{f {}}} {
}
}
proc ngspice::get_current {n} {
global path graph_raw_level
set path [string range [xschem get sch_path] 1 end]
# skip hierarchy components above the level where raw file has been loaded.
# node path names to look up in raw file begin from there.
set skip 0
while { $skip < $graph_raw_level } {
regsub {^[^.]*\.} $path {} path
incr skip
}
set n [string tolower $n]
set prefix [string range $n 0 0]
#puts "ngspice::get_current: path=$path n=$n"
set n $path$n
if { ![sim_is_xyce] } {
if {$path ne {} } {
set n $prefix.$n
}
if { ![regexp $prefix {[ve]}] } {
set n @$n
}
}
set n i($n)
#puts "ngspice::get_current --> $n"
set err [catch {set ngspice::ngspice_data($n)} res]
if { $err } {
set res {?}
} else {
if { abs($res) <1e-3 && $res != 0.0} {
set res [ format %.4e $res ]
} else {
set res [ format %.4g $res ]
}
}
# puts "$n --> $res"
return $res
}
proc ngspice::get_diff_voltage {n m} {
global path graph_raw_level
set path [string range [xschem get sch_path] 1 end]
# skip hierarchy components above the level where raw file has been loaded.
# node path names to look up in raw file begin from there.
set skip 0
while { $skip < $graph_raw_level } {
regsub {^[^.]*\.} $path {} path
incr skip
}
set n [string tolower $n]
set m [string tolower $m]
set nn $path$n
set mm $path$m
set errn [catch {set ngspice::ngspice_data($nn)} resn]
if {$errn} {
set nn v(${path}${n})
set errn [catch {set ngspice::ngspice_data($nn)} resn]
}
set errm [catch {set ngspice::ngspice_data($mm)} resm]
if {$errm} {
set mm v(${path}${m})
set errm [catch {set ngspice::ngspice_data($mm)} resm]
}
if { $errn || $errm} {
set res {?}
} else {
set res [expr {$resn - $resm}]
if { abs($res) <1e-5} {
set res 0
} elseif { abs($res) <1e-3 && $res != 0.0} {
set res [ format %.4e $res ]
} else {
set res [ format %.4g $res ]
}
}
return $res
}
proc ngspice::get_voltage {n} {
global path graph_raw_level
set path [string range [xschem get sch_path] 1 end]
# skip hierarchy components above the level where raw file has been loaded.
# node path names to look up in raw file begin from there.
set skip 0
while { $skip < $graph_raw_level } {
regsub {^[^.]*\.} $path {} path
incr skip
}
set n [string tolower $n]
# puts "ngspice::get_voltage: path=$path n=$n"
set node $path$n
set err [catch {set ngspice::ngspice_data($node)} res]
if {$err} {
set node v(${path}${n})
# puts "ngspice::get_voltage: trying $node"
set err [catch {set ngspice::ngspice_data($node)} res]
}
if { $err } {
set res {?}
} else {
if { abs($res) <1e-5} {
set res 0
} elseif { abs($res) <1e-3 && $res != 0.0} {
set res [ format %.4e $res ]
} else {
set res [ format %.4g $res ]
}
}
return $res
}
proc ngspice::get_node {n} {
global path graph_raw_level
set path [string range [xschem get sch_path] 1 end]
# skip hierarchy components above the level where raw file has been loaded.
# node path names to look up in raw file begin from there.
set skip 0
while { $skip < $graph_raw_level } {
regsub {^[^.]*\.} $path {} path
incr skip
}
set n [string tolower $n]
# n may contain $path, so substitute its value
set n [ subst -nocommand $n ]
set err [catch {set ngspice::ngspice_data($n)} res]
if { $err } {
set res {?}
} else {
if { abs($res) <1e-3 && $res != 0.0} {
set res [ format %.4e $res ]
} else {
set res [ format %.4g $res ]
}
}
return $res
}
# if { [info exists ::has_x] } {bind .drw <Alt-a> {puts {Annotating...}; ngspice::annotate} }

View File

@ -3029,7 +3029,7 @@ const char *translate(int inst, const char* s)
size_t len;
int idx;
double val;
char valstr[120];
const char *valstr;
if(path) {
int skip = 0;
/* skip path components that are above the level where raw file was loaded */
@ -3050,15 +3050,13 @@ const char *translate(int inst, const char* s)
val = xctx->graph_values[idx][xctx->graph_annotate_p];
}
if(idx < 0) {
my_snprintf(valstr, S(valstr), "");
} else if( fabs(val) < 1.0e-5) {
my_snprintf(valstr, S(valstr), "0");
} else if( fabs(val) < 1.0e-3 && val != 0.0) {
my_snprintf(valstr, S(valstr), "%.4e", val);
valstr = "";
xctx->tok_size = 0;
len = 0;
} else {
my_snprintf(valstr, S(valstr), "%.4g", val);
valstr = dtoa_eng(val);
len = xctx->tok_size;
}
len = strlen(valstr);
if(len) {
STR_ALLOC(&result, len + result_pos, &size);
memcpy(result+result_pos, valstr, len+1);
@ -3083,7 +3081,7 @@ const char *translate(int inst, const char* s)
size_t len;
int idx1, idx2;
double val = 0.0, val1 = 0.0, val2 = 0.0;
char valstr[120];
const char *valstr;
if(path) {
int skip = 0;
/* skip path components that are above the level where raw file was loaded */
@ -3116,15 +3114,13 @@ const char *translate(int inst, const char* s)
}
val = val1 - val2;
if(idx1 < 0 || idx2 < 0) {
my_snprintf(valstr, S(valstr), "");
} else if( fabs(val) < 1.0e-5) {
my_snprintf(valstr, S(valstr), "0");
} else if( fabs(val) < 1.0e-3 && val != 0.0) {
my_snprintf(valstr, S(valstr), "%.4e", val);
valstr = "";
xctx->tok_size = 0;
len = 0;
} else {
my_snprintf(valstr, S(valstr), "%.4g", val);
valstr = dtoa_eng(val);
len = xctx->tok_size;
}
len = strlen(valstr);
if(len) {
STR_ALLOC(&result, len + result_pos, &size);
memcpy(result+result_pos, valstr, len+1);
@ -3148,7 +3144,7 @@ const char *translate(int inst, const char* s)
size_t len;
int idx;
double val;
char valstr[120];
const char *valstr;
if(path) {
int skip = 0;
/* skip path components that are above the level where raw file was loaded */
@ -3181,13 +3177,13 @@ const char *translate(int inst, const char* s)
val = xctx->graph_values[idx][xctx->graph_annotate_p];
}
if(idx < 0) {
my_snprintf(valstr, S(valstr), "");
} else if( fabs(val) < 1.0e-3 && val != 0.0) {
my_snprintf(valstr, S(valstr), "%.4e", val);
valstr = "";
xctx->tok_size = 0;
len = 0;
} else {
my_snprintf(valstr, S(valstr), "%.4g", val);
valstr = dtoa_eng(val);
len = xctx->tok_size;
}
len = strlen(valstr);
if(len) {
STR_ALLOC(&result, len + result_pos, &size);
memcpy(result+result_pos, valstr, len+1);

View File

@ -690,7 +690,7 @@ typedef struct {
/* graph box (smaller than rect container due to margins) */
double x1, y1, x2, y2, w, h;
double gx1, gy1, gx2, gy2, gw, gh;
double master_gx1, master_gx2, master_gw;
double master_gx1, master_gx2, master_gw, master_cx;
/* y area range for digital graphs */
double ypos1, ypos2, posh;
double marginx; /* will be recalculated later */
@ -1317,6 +1317,7 @@ extern size_t my_mstrcat(int id, char **str, const char *append_str, ...);
extern char *my_itoa(int i);
extern double atof_spice(const char *s);
extern char *dtoa(double i);
extern char *dtoa_eng(double i);
extern char *dtoa_prec(double i);
extern double my_round(double a);
extern double round_to_n_digits(double x, int n);

View File

@ -266,7 +266,6 @@ proc execute_fileevent {id} {
}
}
proc execute_wait {status args} {
global execute
set id [eval execute $status $args]
@ -347,6 +346,33 @@ proc sframe {container} {
}
#### /Scrollable frame
## convert number to engineering form
proc to_eng {i} {
set suffix {}
set absi [expr {abs($i)}]
if {$absi == 0.0} { set mult 1 ; set suffix {}
} elseif {$absi >=1e12} { set mult 1e-12; set suffix T
} elseif {$absi >=1e9} { set mult 1e-9 ; set suffix G
} elseif {$absi >=1e6} { set mult 1e-6 ; set suffix M
} elseif {$absi >=1e3} { set mult 1e-3 ; set suffix k
} elseif {$absi >=0.1} { set mult 1 ; set suffix {}
} elseif {$absi >=1e-3} { set mult 1e3 ; set suffix m
} elseif {$absi >=1e-6} { set mult 1e6 ; set suffix u
} elseif {$absi >=1e-9} { set mult 1e9 ; set suffix n
} elseif {$absi >=1e-12} { set mult 1e12 ; set suffix p
} elseif {$absi >=1e-15} { set mult 1e15 ; set suffix f
} else { set mult 1e18 ; set suffix a}
if {$suffix ne {}} {
set i [expr {$i * $mult}]
set s [format {%.5g%s} $i $suffix]
} else {
set s [format {%.5g} $i]
}
return $s
}
## evaluate expression. if expression has errors or does not evaluate return expression as is
proc ev {s} {
if {![catch {expr $s} res]} {
@ -668,6 +694,125 @@ proc setup_recent_menu { {in_new_window 0} { topwin {} } } {
}
}
## ngspice:: raw file access functions
namespace eval ngspice {
# Create a variable inside the namespace
variable ngspice_data
variable op_point_read
}
proc ngspice::get_current {n} {
global path graph_raw_level
set path [string range [xschem get sch_path] 1 end]
# skip hierarchy components above the level where raw file has been loaded.
# node path names to look up in raw file begin from there.
set skip 0
while { $skip < $graph_raw_level } {
regsub {^[^.]*\.} $path {} path
incr skip
}
set n [string tolower $n]
set prefix [string range $n 0 0]
#puts "ngspice::get_current: path=$path n=$n"
set n $path$n
if { ![sim_is_xyce] } {
if {$path ne {} } {
set n $prefix.$n
}
if { ![regexp $prefix {[ve]}] } {
set n @$n
}
}
set n i($n)
#puts "ngspice::get_current --> $n"
set err [catch {set ngspice::ngspice_data($n)} res]
if { $err } {
set res {?}
}
# puts "$n --> $res"
return $res
}
proc ngspice::get_diff_voltage {n m} {
global path graph_raw_level
set path [string range [xschem get sch_path] 1 end]
# skip hierarchy components above the level where raw file has been loaded.
# node path names to look up in raw file begin from there.
set skip 0
while { $skip < $graph_raw_level } {
regsub {^[^.]*\.} $path {} path
incr skip
}
set n [string tolower $n]
set m [string tolower $m]
set nn $path$n
set mm $path$m
set errn [catch {set ngspice::ngspice_data($nn)} resn]
if {$errn} {
set nn v(${path}${n})
set errn [catch {set ngspice::ngspice_data($nn)} resn]
}
set errm [catch {set ngspice::ngspice_data($mm)} resm]
if {$errm} {
set mm v(${path}${m})
set errm [catch {set ngspice::ngspice_data($mm)} resm]
}
if { $errn || $errm} {
set res {?}
}
return $res
}
proc ngspice::get_voltage {n} {
global path graph_raw_level
set path [string range [xschem get sch_path] 1 end]
# skip hierarchy components above the level where raw file has been loaded.
# node path names to look up in raw file begin from there.
set skip 0
while { $skip < $graph_raw_level } {
regsub {^[^.]*\.} $path {} path
incr skip
}
set n [string tolower $n]
# puts "ngspice::get_voltage: path=$path n=$n"
set node $path$n
set err [catch {set ngspice::ngspice_data($node)} res]
if {$err} {
set node v(${path}${n})
# puts "ngspice::get_voltage: trying $node"
set err [catch {set ngspice::ngspice_data($node)} res]
}
if { $err } {
set res {?}
}
return $res
}
proc ngspice::get_node {n} {
global path graph_raw_level
set path [string range [xschem get sch_path] 1 end]
# skip hierarchy components above the level where raw file has been loaded.
# node path names to look up in raw file begin from there.
set skip 0
while { $skip < $graph_raw_level } {
regsub {^[^.]*\.} $path {} path
incr skip
}
set n [string tolower $n]
# n may contain $path, so substitute its value
set n [ subst -nocommand $n ]
set err [catch {set ngspice::ngspice_data($n)} res]
if { $err } {
set res {?}
}
return $res
}
## end ngspice:: functions
proc sim_is_ngspice {} {
global sim

View File

@ -323,7 +323,7 @@ C {ngspice_get_expr.sym} 330 -900 0 1 {name=r17
node="[ngspice::get_current v2]"
descr = current
}
C {ngspice_get_expr.sym} 360 -1040 0 0 {name=r18
C {ngspice_get_expr.sym} 380 -1030 0 0 {name=r18
node="[ngspice::get_current \{r2[i]\}]"
descr = current
}
@ -356,7 +356,7 @@ node="[format %.4g [expr ([ngspice::get_voltage e11] - [ngspice::get_voltage ga]
descr = power
}
C {ngspice_get_expr.sym} 1000 -710 0 0 {name=r20
node="[ngspice::get_current \{r0[i]\}]"
node="[to_eng [ngspice::get_current \{r0[i]\}]]"
descr = current
}
C {ngspice_get_expr.sym} 280 -200 2 1 {name=r3

View File

@ -20,7 +20,7 @@ subdivx=1
node=s_vec
color=4
dataset=0
unitx=u
unitx=1
logx=0
logy=0
}