You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

154 lines
5.4 KiB

/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Gordon Jacobs
Modified: 2001 Jon Engelbert
**********/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "cswdefs.h"
#include "ngspice/fteext.h"
#include "ngspice/trandefs.h"
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
int
CSWload(GENmodel *inModel, CKTcircuit *ckt)
/* actually load the current values into the
* sparse matrix previously provided
*/
{
CSWmodel *model = (CSWmodel*)inModel;
CSWinstance *here;
double g_now;
double i_ctrl;
double previous_state = -1;
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 */
for( ; model != NULL; model = model->CSWnextModel ) {
/* loop through all the instances of the model */
for (here = model->CSWinstances; here != NULL ;
here=here->CSWnextInstance) {
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 */
if(ckt->CKTmode & (MODEINITFIX|MODEINITJCT)) {
if(here->CSWzero_stateGiven) {
/* switch specified "on" */
if ((model->CSWiHysteresis >= 0) && (i_ctrl > (model->CSWiThreshold + model->CSWiHysteresis)))
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 {
if ((model->CSWiHysteresis >= 0) && (i_ctrl < (model->CSWiThreshold - model->CSWiHysteresis)))
current_state = REALLY_OFF;
else if ((model->CSWiHysteresis < 0) && (i_ctrl < (model->CSWiThreshold + model->CSWiHysteresis)))
current_state = REALLY_OFF;
else
current_state = HYST_OFF;
}
} else if (ckt->CKTmode & (MODEINITSMSIG)) {
current_state = previous_state;
} else if (ckt->CKTmode & (MODEINITFLOAT)) {
/* use state0 since INITTRAN or INITPRED already called */
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 != old_current_state) {
ckt->CKTnoncon++; /* ensure one more iteration */
ckt->CKTtroubleElt = (GENinstance *) here;
}
} else if (ckt->CKTmode & (MODEINITTRAN|MODEINITPRED)) {
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 cswload");
}
}
}
*(ckt->CKTstates[0] + here->CSWstate) = current_state;
*(ckt->CKTstates[1] + here->CSWstate) = previous_state;
if ((current_state == REALLY_ON) || (current_state == HYST_ON))
g_now = model->CSWonConduct;
else
g_now = model->CSWoffConduct;
here->CSWcond = g_now;
*(here->CSWposPosPtr) += g_now;
*(here->CSWposNegPtr) -= g_now;
*(here->CSWnegPosPtr) -= g_now;
*(here->CSWnegNegPtr) += g_now;
}
}
return(OK);
}