Add current measurement for device XYZ using I(XYZ)

This commit is contained in:
h_vogt 2015-12-13 10:28:04 +01:00 committed by rlar
parent 95f092ad12
commit caebd2dfad
1 changed files with 206 additions and 0 deletions

View File

@ -123,6 +123,7 @@ static char *inp_remove_ws(char *s);
static void inp_compat(struct line *deck);
static void inp_bsource_compat(struct line *deck);
static void inp_temper_compat(struct line *card);
static void inp_meas_current(struct line *card);
static void inp_dot_if(struct line *deck);
static char *inp_modify_exp(char* expression);
static struct func_temper *inp_new_func(char *funcname, char *funcbody, struct line *card,
@ -538,6 +539,7 @@ inp_readall(FILE *fp, char *dir_name, bool comfile, bool intfile)
if (inp_compat_mode != COMPATMODE_SPICE3) {
/* Do all the compatibility stuff here */
working = cc->li_next;
inp_meas_current(working);
/* E, G, L, R, C compatibility transformations */
inp_compat(working);
working = cc->li_next;
@ -6200,3 +6202,207 @@ inp_quote_params(struct line *c, struct line *end_c, struct dependency *deps, in
}
}
}
/* storage for devices which get voltage source added */
struct replace_currm
{
struct line *s_start;
struct line *cline;
char *rtoken;
struct replace_currm *next;
};
/* Measure current in node 1 of all devices, e.g. I, B, F, and G.
I(V...) will be ignored, however H, E nonlinear voltage
sources may be converted later
to B source, therefore we need to add current measurement here.
First find all ocurrencies of i(XYZ), store their cards, then
search for XYZ, but only within respective subcircuit, or if
all happens at top level. Other hierarchy is ignored for now.
Replace I(XYZ) bx I(V_XYZ), add voltage source V_XYZ with
suitable extra nodes.
*/
static void
inp_meas_current(struct line *deck)
{
struct line *card, *subc_start = NULL, *subc_prev = NULL;
struct replace_currm *new_rep, *act_rep = NULL, *rep = NULL;
char *s, *t, *u, *v;
int skip_control = 0, subs = 0;
/* scan through deck and find i(xyz), replace by i(v_xyz) */
for (card = deck; card; card = card->li_next) {
char *curr_line = card->li_line;
/* exclude any command inside .control ... .endc */
if (ciprefix(".control", curr_line)) {
skip_control++;
continue;
}
else if (ciprefix(".endc", curr_line)) {
skip_control--;
continue;
}
else if (skip_control > 0) {
continue;
}
if (*curr_line == '*')
continue;
if (*curr_line == '.') {
if (ciprefix(".subckt", curr_line)) {
subs++;
subc_prev = subc_start;
subc_start = card;
}
else if (ciprefix(".ends", curr_line)) {
subs--;
subc_start = subc_prev;
}
else
continue;
}
if (!strstr(curr_line, "i("))
continue;
s = v = stripWhiteSpacesInsideParens(curr_line);
while (s) {
/* i( may occur more than once in a line */
s = u = strstr(s, "i(");
/* we have found it, but not (in error) at the beginning of the line */
if (s && s > v) {
/* '{' if at beginning of expression */
if (is_arith_char(s[-1]) || s[-1] == '{') {
s += 2;
if (*s == 'v') {
// printf("i(v...) found in\n%s\n not converted!\n\n", curr_line);
continue;
}
else {
char *beg_str, *new_str;
get_r_paren(&u);
/* token containing name of devices to be measured */
t = copy_substring(s, --u);
if (ft_ngdebug)
printf("i(%s) found in\n%s\n\n", t, curr_line);
/* new entry to the end of struct rep */
new_rep = TMALLOC(struct replace_currm, 1);
new_rep->s_start = subc_start;
new_rep->next = NULL;
new_rep->cline = card;
new_rep->rtoken = t;
if (act_rep) {
act_rep->next = new_rep;
act_rep = act_rep->next;
}
else
rep = act_rep = new_rep;
/* change line, convert i(XXX) to i(v_XXX) */
beg_str = copy_substring(v, s);
new_str = tprintf("%s%s%s", beg_str, "v_", s);
if (ft_ngdebug)
printf("converted to\n%s\n\n", new_str);
tfree(curr_line);
tfree(v);
card->li_line = s = v = new_str;
s++;
tfree(beg_str);
}
}
else
s++;
}
}
}
/* return if we did not find any i( */
if (rep == NULL)
return;
/* scan through all the devices, search for xyz, modify node 1 by adding _vmeas,
add a line with zero voltage v_xyz, having original node 1 and modified node 1.
Do this within the top level or the same level of subcircuit only. */
new_rep = rep;
for (; rep; rep = rep->next) {
card = rep->s_start;
subs = 0;
if (card)
card = card->li_next;
else
card = deck;
for (; card; card = card->li_next) {
char *tok, *new_tok, *node1, *new_line;
char *curr_line = card->li_line;
/* exclude any command inside .control ... .endc */
if (ciprefix(".control", curr_line)) {
skip_control++;
continue;
}
else if (ciprefix(".endc", curr_line)) {
skip_control--;
continue;
}
else if (skip_control > 0) {
continue;
}
if (*curr_line == '*')
continue;
if (*curr_line == '.') {
if (ciprefix(".subckt", curr_line))
subs++;
else if (ciprefix(".ends", curr_line))
subs--;
else
continue;
}
if (subs > 0)
continue;
/* We are at now top level or in top level of subcircuit
where i(xyz) has been found */
tok = gettok(&curr_line);
/* done when end of subcircuit is reached */
if (eq(".ends", tok) && rep->s_start)
break;
if (eq(rep->rtoken, tok)) {
node1 = gettok(&curr_line);
/* Add _vmeas only once to first device node.
Continue if we already have modified device "tok" */
if (!strstr(node1, "_vmeas")) {
new_line = tprintf("%s %s_vmeas %s", tok, node1, curr_line);
tfree(card->li_line);
card->li_line = new_line;
}
new_tok = tprintf("v_%s", tok);
/* We have already added a line v_xyz to the deck */
if (!ciprefix(new_tok, card->li_next->li_line)) {
/* add new line */
new_line = tprintf("%s %s %s_vmeas 0", new_tok, node1, node1);
/* insert new_line after card->li_line */
card->li_next = xx_new_line(card->li_next, new_line,
card->li_linenum + 1, 0);
}
tfree(new_tok);
tfree(node1);
}
tfree(tok);
}
}
/* free rep */
while (new_rep) {
struct replace_currm *repn = new_rep->next;
tfree(new_rep->rtoken);
tfree(new_rep);
new_rep = repn;
}
}