1 /**********
2 Copyright 1990 Regents of the University of California. All rights reserved.
3 Author: 1985 Gordon Jacobs
4 Modified: 2001 Jon Engelbert
5 **********/
6
7 #include "ngspice/ngspice.h"
8 #include "ngspice/cktdefs.h"
9 #include "ngspice/fteext.h"
10 #include "swdefs.h"
11 #include "ngspice/trandefs.h"
12 #include "ngspice/sperror.h"
13 #include "ngspice/suffix.h"
14
15
16 int
SWload(GENmodel * inModel,CKTcircuit * ckt)17 SWload(GENmodel *inModel, CKTcircuit *ckt)
18 {
19 SWmodel *model = (SWmodel *) inModel;
20 SWinstance *here;
21 double g_now;
22 double v_ctrl;
23 double previous_state = -1;
24 double current_state = -1;
25 double old_current_state = -1;
26 double REALLY_OFF = 0, REALLY_ON = 1; // switch is on or off, not in hysteresis region.
27 double HYST_OFF = 2, HYST_ON = 3; // switch is on or off while control value is in hysteresis region.
28 // double previous_region = -1;
29 // double current_region = -1;
30
31 for (; model; model = SWnextModel(model))
32 for (here = SWinstances(model); here; here = SWnextInstance(here)) {
33
34 old_current_state = ckt->CKTstate0[here->SWswitchstate];
35 previous_state = ckt->CKTstate1[here->SWswitchstate];
36
37 v_ctrl =
38 ckt->CKTrhsOld[here->SWposCntrlNode] -
39 ckt->CKTrhsOld[here->SWnegCntrlNode];
40
41 /* decide the state of the switch */
42
43 if (ckt->CKTmode & (MODEINITFIX | MODEINITJCT)) {
44
45 if (here->SWzero_stateGiven) {
46 /* switch specified "on" */
47 if (model->SWvHysteresis >= 0 && v_ctrl > model->SWvThreshold + model->SWvHysteresis)
48 current_state = REALLY_ON;
49 else if (model->SWvHysteresis < 0 && v_ctrl > model->SWvThreshold - model->SWvHysteresis)
50 current_state = REALLY_ON;
51 else
52 current_state = HYST_ON;
53 } else {
54 if (model->SWvHysteresis >= 0 && v_ctrl < model->SWvThreshold - model->SWvHysteresis)
55 current_state = REALLY_OFF;
56 else if (model->SWvHysteresis < 0 && v_ctrl < model->SWvThreshold + model->SWvHysteresis)
57 current_state = REALLY_OFF;
58 else
59 current_state = HYST_OFF;
60 }
61
62 } else if (ckt->CKTmode & (MODEINITSMSIG)) {
63
64 current_state = previous_state;
65
66 } else if (ckt->CKTmode & (MODEINITFLOAT)) {
67
68 /* use state0 since INITTRAN or INITPRED already called */
69 if (model->SWvHysteresis > 0) {
70 if (v_ctrl > (model->SWvThreshold + model->SWvHysteresis))
71 current_state = REALLY_ON;
72 else if (v_ctrl < (model->SWvThreshold - model->SWvHysteresis))
73 current_state = REALLY_OFF;
74 else
75 current_state = old_current_state;
76 } else { // negative hysteresis case.
77 if (v_ctrl > (model->SWvThreshold - model->SWvHysteresis))
78 current_state = REALLY_ON;
79 else if (v_ctrl < (model->SWvThreshold + model->SWvHysteresis))
80 current_state = REALLY_OFF;
81 else { // in hysteresis... change value if going from low to hysteresis, or from hi to hysteresis.
82 // if previous state was in hysteresis, then don't change the state..
83 if (previous_state == HYST_OFF || previous_state == HYST_ON)
84 current_state = previous_state;
85 else if (previous_state == REALLY_ON)
86 current_state = HYST_OFF;
87 else if (previous_state == REALLY_OFF)
88 current_state = HYST_ON;
89 else
90 internalerror("bad value for previous state in swload");
91 }
92 }
93
94 if (current_state != old_current_state) {
95 ckt->CKTnoncon++; /* ensure one more iteration */
96 ckt->CKTtroubleElt = (GENinstance *) here;
97 }
98
99 } else if (ckt->CKTmode & (MODEINITTRAN | MODEINITPRED)) {
100
101 if (model->SWvHysteresis > 0) {
102 if (v_ctrl > (model->SWvThreshold + model->SWvHysteresis))
103 current_state = REALLY_ON;
104 else if (v_ctrl < (model->SWvThreshold - model->SWvHysteresis))
105 current_state = REALLY_OFF;
106 else
107 current_state = previous_state;
108 } else { // negative hysteresis case.
109 if (v_ctrl > (model->SWvThreshold - model->SWvHysteresis))
110 current_state = REALLY_ON;
111 else if (v_ctrl < (model->SWvThreshold + model->SWvHysteresis))
112 current_state = REALLY_OFF;
113 else {
114 current_state = 0.0;
115 if (previous_state == HYST_ON || previous_state == HYST_OFF)
116 current_state = previous_state;
117 else if (previous_state == REALLY_ON)
118 current_state = REALLY_OFF;
119 else if (previous_state == REALLY_OFF)
120 current_state = REALLY_ON;
121 }
122 }
123 }
124
125 // code added to force the state to be updated.
126 // there is a possible problem. What if, during the transient analysis, the time is stepped
127 // forward enough to change the switch's state, but that time point is rejected as being too
128 // distant and then the time is pushed back to a time before the switch changed states.
129 // After analyzing the transient code, it seems that this is not a problem because state updating
130 // occurs before the convergence loop in transient processing.
131
132 ckt->CKTstate0[here->SWswitchstate] = current_state;
133 ckt->CKTstate0[here->SWctrlvalue] = v_ctrl;
134
135 if (current_state == REALLY_ON || current_state == HYST_ON)
136 g_now = model->SWonConduct;
137 else
138 g_now = model->SWoffConduct;
139
140 here->SWcond = g_now;
141
142 *(here->SWposPosPtr) += g_now;
143 *(here->SWposNegPtr) -= g_now;
144 *(here->SWnegPosPtr) -= g_now;
145 *(here->SWnegNegPtr) += g_now;
146 }
147
148 return OK;
149 }
150