Added a patch to csw and sw from Jon Engelbert dealing with negative histeresys

This commit is contained in:
pnenzi 2001-04-25 18:28:20 +00:00
parent 07b5fae7d8
commit 0dae4607a0
4 changed files with 186 additions and 110 deletions

View File

@ -1,7 +1,7 @@
/********** /**********
Copyright 1990 Regents of the University of California. All rights reserved. Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Gordon Jacobs Author: 1985 Gordon Jacobs
Modified: 2000 AlansFixes Modified: 2001 Jon Engelbert
**********/ **********/
#include "ngspice.h" #include "ngspice.h"
@ -25,8 +25,10 @@ CSWload(inModel,ckt)
CSWinstance *here; CSWinstance *here;
double g_now; double g_now;
double i_ctrl; double i_ctrl;
double previous_state; double previous_state = -1;
double current_state; double current_state = -1, old_current_state = -1;
double REALLY_OFF = 0, REALLY_ON = 1; // switch is on or off, not in hysteresis region.
double HYST_OFF = 2, HYST_ON = 3; // switch is on or off while control value is in hysteresis region.
/* loop through all the switch models */ /* loop through all the switch models */
for( ; model != NULL; model = model->CSWnextModel ) { for( ; model != NULL; model = model->CSWnextModel ) {
@ -34,7 +36,13 @@ CSWload(inModel,ckt)
/* loop through all the instances of the model */ /* loop through all the instances of the model */
for (here = model->CSWinstances; here != NULL ; for (here = model->CSWinstances; here != NULL ;
here=here->CSWnextInstance) { here=here->CSWnextInstance) {
if (here->CSWowner != ARCHme) continue;
if (here->CSWowner != ARCHme) continue;
old_current_state = *(ckt->CKTstates[0] + here->CSWstate);
previous_state = *(ckt->CKTstates[1] + here->CSWstate);
i_ctrl = *(ckt->CKTrhsOld +
here->CSWcontBranch);
/* decide the state of the switch */ /* decide the state of the switch */
@ -42,71 +50,94 @@ CSWload(inModel,ckt)
if(here->CSWzero_stateGiven) { if(here->CSWzero_stateGiven) {
/* switch specified "on" */ /* switch specified "on" */
*(ckt->CKTstate0 + here->CSWstate) = 1.0; if ((model->CSWiHysteresis >= 0) && (i_ctrl > (model->CSWiThreshold + model->CSWiHysteresis)))
current_state = 1.0; current_state = REALLY_ON;
else if ((model->CSWiHysteresis < 0) && (i_ctrl > (model->CSWiThreshold - model->CSWiHysteresis)))
current_state = REALLY_ON;
else
current_state = HYST_ON;
} else { } else {
*(ckt->CKTstate0 + here->CSWstate) = 0.0; if ((model->CSWiHysteresis >= 0) && (i_ctrl < (model->CSWiThreshold - model->CSWiHysteresis)))
current_state = 0.0; current_state = REALLY_OFF;
else if ((model->CSWiHysteresis < 0) && (i_ctrl < (model->CSWiThreshold + model->CSWiHysteresis)))
current_state = REALLY_OFF;
else
current_state = HYST_OFF;
} }
*(ckt->CKTstate0 + (here->CSWstate+1)) = 0;
} else if (ckt->CKTmode & (MODEINITSMSIG)) { } else if (ckt->CKTmode & (MODEINITSMSIG)) {
previous_state = *(ckt->CKTstate0 + here->CSWstate);
current_state = previous_state; current_state = previous_state;
} else if (ckt->CKTmode & (MODEINITFLOAT)) { } else if (ckt->CKTmode & (MODEINITFLOAT)) {
/* use state0 since INITTRAN or INITPRED already called */ /* use state0 since INITTRAN or INITPRED already called */
previous_state = *(ckt->CKTstate0 + here->CSWstate);
i_ctrl = *(ckt->CKTrhsOld +
here->CSWcontBranch);
if(i_ctrl > (model->CSWiThreshold+model->CSWiHysteresis)) {
*(ckt->CKTstate0 + here->CSWstate) = 1.0;
current_state = 1.0;
}
else if(i_ctrl < (model->CSWiThreshold -
model->CSWiHysteresis)) {
*(ckt->CKTstate0 + here->CSWstate) = 0.0;
current_state = 0.0;
}
else {
current_state = previous_state;
}
*(ckt->CKTstate0 + (here->CSWstate+1)) = i_ctrl; if (model->CSWiHysteresis > 0) {
if (i_ctrl > (model->CSWiThreshold + model->CSWiHysteresis)) {
current_state = REALLY_ON;
} else if (i_ctrl < (model->CSWiThreshold - model->CSWiHysteresis)) {
current_state = REALLY_OFF;
} else {
current_state = previous_state;
}
} else {
if (i_ctrl > (model->CSWiThreshold - model->CSWiHysteresis)) {
current_state = REALLY_ON;
} else if (i_ctrl < (model->CSWiThreshold + model->CSWiHysteresis)) {
current_state = REALLY_OFF;
} else { // in hysteresis... change value if going from low to hysteresis, or from hi to hysteresis.
// if previous state was in hysteresis, then don't change the state..
if ((previous_state == HYST_OFF) || (previous_state == HYST_ON)) {
current_state = previous_state;
} else if (previous_state == REALLY_ON) {
current_state = HYST_OFF;
} else if (previous_state == REALLY_OFF) {
current_state = HYST_ON;
} else
internalerror("bad value for previous region in swload");
}
}
if(current_state != previous_state) { if(current_state != old_current_state) {
ckt->CKTnoncon++; /* ensure one more iteration */ ckt->CKTnoncon++; /* ensure one more iteration */
ckt->CKTtroubleElt = (GENinstance *) here; ckt->CKTtroubleElt = (GENinstance *) here;
} }
} else if (ckt->CKTmode & (MODEINITTRAN|MODEINITPRED)) { } else if (ckt->CKTmode & (MODEINITTRAN|MODEINITPRED)) {
previous_state = *(ckt->CKTstate1 + here->CSWstate); if (model->CSWiHysteresis > 0) {
i_ctrl = *(ckt->CKTrhsOld + if (i_ctrl > (model->CSWiThreshold + model->CSWiHysteresis)) {
here->CSWcontBranch); current_state = REALLY_ON;
} else if (i_ctrl < (model->CSWiThreshold - model->CSWiHysteresis)) {
current_state = REALLY_OFF;
} else {
current_state = previous_state;
}
} else {
if (i_ctrl > (model->CSWiThreshold - model->CSWiHysteresis)) {
current_state = REALLY_ON;
} else if (i_ctrl < (model->CSWiThreshold + model->CSWiHysteresis)) {
current_state = REALLY_OFF;
} else { // in hysteresis... change value if going from low to hysteresis, or from hi to hysteresis.
// if previous state was in hysteresis, then don't change the state..
if ((previous_state == HYST_OFF) || (previous_state == HYST_ON)) {
current_state = previous_state;
} else if (previous_state == REALLY_ON) {
current_state = HYST_OFF;
} else if (previous_state == REALLY_OFF) {
current_state = HYST_ON;
} else
internalerror("bad value for previous region in cswload");
}
}
}
if(i_ctrl > (model->CSWiThreshold+model->CSWiHysteresis)) { *(ckt->CKTstates[0] + here->CSWstate) = current_state;
current_state = 1; *(ckt->CKTstates[1] + here->CSWstate) = previous_state;
} else if(i_ctrl < (model->CSWiThreshold - if ((current_state == REALLY_ON) || (current_state == HYST_ON))
model->CSWiHysteresis)) { g_now = model->CSWonConduct;
current_state = 0; else
} else { g_now = model->CSWoffConduct;
current_state = previous_state;
}
if(current_state == 0) {
*(ckt->CKTstate0 + here->CSWstate) = 0.0;
} else {
*(ckt->CKTstate0 + here->CSWstate) = 1.0;
}
*(ckt->CKTstate0 + (here->CSWstate+1)) = i_ctrl;
}
g_now = current_state?(model->CSWonConduct):(model->CSWoffConduct);
here->CSWcond = g_now; here->CSWcond = g_now;
*(here->CSWposPosptr) += g_now; *(here->CSWposPosptr) += g_now;

View File

@ -1,6 +1,7 @@
/********** /**********
Copyright 1990 Regents of the University of California. All rights reserved. Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Gordon Jacobs Author: 1985 Gordon Jacobs
Modified: 2001 Jon Englebert
**********/ **********/
/* /*
*/ */
@ -40,7 +41,8 @@ CSWmParam(param,value,inModel)
break; break;
case CSW_IHYS: case CSW_IHYS:
/* take absolute value of hysteresis voltage */ /* take absolute value of hysteresis voltage */
model->CSWiHysteresis = fabs(value->rValue); // model->CSWiHysteresis = fabs(value->rValue);
model->CSWiHysteresis = value->rValue;
model->CSWhystGiven = TRUE; model->CSWhystGiven = TRUE;
break; break;
default: default:

View File

@ -1,7 +1,7 @@
/********** /**********
Copyright 1990 Regents of the University of California. All rights reserved. Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Gordon Jacobs Author: 1985 Gordon Jacobs
Modified: 2000 AlansFixes Modified: 2001 Jon Engelbert
**********/ **********/
#include "ngspice.h" #include "ngspice.h"
@ -24,8 +24,14 @@ SWload(inModel,ckt)
SWinstance *here; SWinstance *here;
double g_now; double g_now;
double v_ctrl; double v_ctrl;
double previous_state; double previous_state = -1;
double current_state; double current_state = -1;
double old_current_state = -1;
double UNKNOWN = -1;
double REALLY_OFF = 0, REALLY_ON = 1; // switch is on or off, not in hysteresis region.
double HYST_OFF = 2, HYST_ON = 3; // switch is on or off while control value is in hysteresis region.
// double previous_region = -1;
// double current_region = -1;
/* loop through all the switch models */ /* loop through all the switch models */
for( ; model != NULL; model = model->SWnextModel ) { for( ; model != NULL; model = model->SWnextModel ) {
@ -34,78 +40,113 @@ SWload(inModel,ckt)
for (here = model->SWinstances; here != NULL ; for (here = model->SWinstances; here != NULL ;
here=here->SWnextInstance) { here=here->SWnextInstance) {
if (here->SWowner != ARCHme) continue; if (here->SWowner != ARCHme) continue;
old_current_state = *(ckt->CKTstates[0] + here->SWstate);
previous_state = *(ckt->CKTstates[1] + here->SWstate);
/* decide the state of the switch */ v_ctrl = *(ckt->CKTrhsOld + here->SWposCntrlNode)
- *(ckt->CKTrhsOld + here->SWnegCntrlNode);
/* decide the state of the switch */
if(ckt->CKTmode & (MODEINITFIX|MODEINITJCT)) { if(ckt->CKTmode & (MODEINITFIX|MODEINITJCT)) {
if(here->SWzero_stateGiven) { if(here->SWzero_stateGiven) {
/* switch specified "on" */ /* switch specified "on" */
*(ckt->CKTstate0 + here->SWstate) = 1.0; if ((model->SWvHysteresis >= 0) && (v_ctrl > (model->SWvThreshold + model->SWvHysteresis)))
current_state = 1.0; current_state = REALLY_ON;
else if ((model->SWvHysteresis < 0) && (v_ctrl > (model->SWvThreshold - model->SWvHysteresis)))
current_state = REALLY_ON;
else
current_state = HYST_ON;
} else { } else {
*(ckt->CKTstate0 + here->SWstate) = 0.0; if ((model->SWvHysteresis >= 0) && (v_ctrl < (model->SWvThreshold - model->SWvHysteresis)))
current_state = 0.0; current_state = REALLY_OFF;
else if ((model->SWvHysteresis < 0) && (v_ctrl < (model->SWvThreshold + model->SWvHysteresis)))
current_state = REALLY_OFF;
else
current_state = HYST_OFF;
} }
*(ckt->CKTstate0 + (here->SWstate+1)) = 0;
} else if (ckt->CKTmode & (MODEINITSMSIG)) { } else if (ckt->CKTmode & (MODEINITSMSIG)) {
previous_state = *(ckt->CKTstate0 + here->SWstate);
current_state = previous_state; current_state = previous_state;
} else if (ckt->CKTmode & (MODEINITFLOAT)) { } else if (ckt->CKTmode & (MODEINITFLOAT)) {
/* use state0 since INITTRAN or INITPRED already called */ /* use state0 since INITTRAN or INITPRED already called */
previous_state = *(ckt->CKTstate0 + here->SWstate); if (model->SWvHysteresis > 0) {
v_ctrl = *(ckt->CKTrhsOld + here->SWposCntrlNode) if (v_ctrl > (model->SWvThreshold + model->SWvHysteresis)) {
- *(ckt->CKTrhsOld + here->SWnegCntrlNode); current_state = REALLY_ON;
if(v_ctrl > (model->SWvThreshold + model->SWvHysteresis)) { } else if (v_ctrl < (model->SWvThreshold - model->SWvHysteresis)) {
*(ckt->CKTstate0 + here->SWstate) = 1.0; current_state = REALLY_OFF;
current_state = 1.0; } else {
} else if(v_ctrl < (model->SWvThreshold - current_state = old_current_state;
model->SWvHysteresis)) { }
*(ckt->CKTstate0 + here->SWstate) = 0.0; } else { // negative hysteresis case.
current_state = 0.0; if (v_ctrl > (model->SWvThreshold - model->SWvHysteresis))
} else { {
current_state = previous_state; current_state = REALLY_ON;
} } else if (v_ctrl < (model->SWvThreshold + model->SWvHysteresis))
{
*(ckt->CKTstate0 + (here->SWstate+1)) = v_ctrl; current_state = REALLY_OFF;
} else { // in hysteresis... change value if going from low to hysteresis, or from hi to hysteresis.
if(current_state != previous_state) { // if previous state was in hysteresis, then don't change the state..
if ((previous_state == HYST_OFF) || (previous_state == HYST_ON)) {
current_state = previous_state;
} else if (previous_state == REALLY_ON) {
current_state = HYST_OFF;
} else if (previous_state == REALLY_OFF) {
current_state = HYST_ON;
} else
internalerror("bad value for previous state in swload");
}
}
if(current_state != old_current_state) {
ckt->CKTnoncon++; /* ensure one more iteration */ ckt->CKTnoncon++; /* ensure one more iteration */
ckt->CKTtroubleElt = (GENinstance *) here; ckt->CKTtroubleElt = (GENinstance *) here;
} }
} else if(ckt->CKTmode & (MODEINITTRAN|MODEINITPRED) ) { } else if(ckt->CKTmode & (MODEINITTRAN|MODEINITPRED) ) {
previous_state = *(ckt->CKTstate1 + here->SWstate); if (model->SWvHysteresis > 0) {
v_ctrl = *(ckt->CKTrhsOld + here->SWposCntrlNode) if (v_ctrl > (model->SWvThreshold + model->SWvHysteresis))
- *(ckt->CKTrhsOld + here->SWnegCntrlNode); current_state = REALLY_ON;
else if (v_ctrl < (model->SWvThreshold - model->SWvHysteresis))
current_state = REALLY_OFF;
else
current_state = previous_state;
} else { // negative hysteresis case.
if (v_ctrl > (model->SWvThreshold - model->SWvHysteresis))
current_state = REALLY_ON;
else if (v_ctrl < (model->SWvThreshold + model->SWvHysteresis))
current_state = REALLY_OFF;
else {
current_state = 0.0;
if ((previous_state == HYST_ON) || (previous_state == HYST_OFF)) {
current_state = previous_state;
} else if (previous_state == REALLY_ON) {
current_state = REALLY_OFF;
} else if (previous_state == REALLY_OFF) {
current_state = REALLY_ON;
}
}
}
}
// code added to force the state to be updated.
// there is a possible problem. What if, during the transient analysis, the time is stepped
// forward enough to change the switch's state, but that time point is rejected as being too
// distant and then the time is pushed back to a time before the switch changed states.
// After analyzing the transient code, it seems that this is not a problem because state updating
// occurs before the convergence loop in transient processing.
*(ckt->CKTstates[0] + here->SWstate) = current_state;
if(v_ctrl > (model->SWvThreshold + model->SWvHysteresis)) { if ((current_state == REALLY_ON) || (current_state == HYST_ON))
current_state = 1.0; g_now = model->SWonConduct;
} else if(v_ctrl < (model->SWvThreshold - else
model->SWvHysteresis)) { g_now = model->SWoffConduct;
current_state = 0.0;
} else {
current_state = previous_state;
}
if(current_state == 0) {
*(ckt->CKTstate0 + here->SWstate) = 0.0;
} else {
*(ckt->CKTstate0 + here->SWstate) = 1.0;
}
*(ckt->CKTstate0 + (here->SWstate+1)) = v_ctrl;
}
g_now = current_state?(model->SWonConduct):(model->SWoffConduct);
here->SWcond = g_now; here->SWcond = g_now;
*(here->SWposPosptr) += g_now; *(here->SWposPosptr) += g_now;

View File

@ -1,6 +1,7 @@
/********** /**********
Copyright 1990 Regents of the University of California. All rights reserved. Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Gordon Jacobs Author: 1985 Gordon Jacobs
Modified: 2001 Jon Engelbert
**********/ **********/
/* /*
*/ */
@ -41,8 +42,9 @@ SWmParam(param,value,inModel)
break; break;
case SW_MOD_VHYS: case SW_MOD_VHYS:
/* take absolute value of hysteresis voltage */ /* take absolute value of hysteresis voltage */
model->SWvHysteresis = (value->rValue < 0) ? -(value->rValue) : // model->SWvHysteresis = (value->rValue < 0) ? -(value->rValue) :
value->rValue; // value->rValue;
model->SWvHysteresis = value->rValue;
model->SWhystGiven = TRUE; model->SWhystGiven = TRUE;
break; break;
default: default: