1 /***************************************************************************
2 JSPICE3 adaptation of Spice3e2 - Copyright (c) Stephen R. Whiteley 1992
3 Copyright 1990 Regents of the University of California. All rights reserved.
4 Authors: UCB CAD Group
5 1992 Stephen R. Whiteley
6 ****************************************************************************/
7
8 #include "spice.h"
9 #include <stdio.h>
10 #include <math.h>
11 #include "devdefs.h"
12 #include "pzdefs.h"
13 #include "sperror.h"
14 #include "util.h"
15 #include "outdata.h"
16 #include "cktext.h"
17
18 #ifdef __STDC__
19 static int PZinit(CKTcircuit*);
20 static int PZpost(CKTcircuit*);
21 #else
22 static int PZinit();
23 static int PZpost();
24 #endif
25
26 #define DEBUG if (0)
27
28
29 /* ARGSUSED */
30 int
PZan(cktp,reset)31 PZan(cktp,reset)
32
33 GENERIC *cktp;
34 int reset;
35 {
36 CKTcircuit *ckt = (CKTcircuit *)cktp;
37 PZAN *pzan = (PZAN *) ckt->CKTcurJob;
38 int error;
39
40 if (ckt->CKTjjPresent) {
41 (*(SPfrontEnd->IFerror))(ERR_FATAL,
42 "PZ analysis not possible with Josephson junctions", NULL);
43 return (OK);
44 }
45 error = PZinit(ckt);
46 if (error != OK)
47 return error;
48
49 /* Calculate small signal parameters at the operating point */
50 error = CKTop(ckt,
51 MODEDCOP | MODEINITJCT,
52 MODEDCOP | MODEINITFLOAT,
53 ckt->CKTdcMaxIter);
54 if (error)
55 return (error);
56
57 ckt->CKTmode = MODEDCOP | MODEINITSMSIG;
58 error = CKTload(ckt);
59 if (error)
60 return (error);
61
62 if (pzan->PZwhich & PZ_DO_POLES) {
63 error = CKTpzSetup(ckt, PZ_DO_POLES);
64 if (error != OK)
65 return (error);
66 error = CKTpzFindZeros(ckt,
67 (GENERIC**)&pzan->PZpoleList, &pzan->PZnPoles);
68 if (error != OK)
69 return (error);
70 }
71
72 if (pzan->PZwhich & PZ_DO_ZEROS) {
73 error = CKTpzSetup(ckt, PZ_DO_ZEROS);
74 if (error != OK)
75 return (error);
76 error = CKTpzFindZeros(ckt,
77 (GENERIC**)&pzan->PZzeroList, &pzan->PZnZeros);
78 if (error != OK)
79 return (error);
80 }
81
82 return PZpost(ckt);
83 }
84
85
86 static int
PZinit(ckt)87 PZinit(ckt)
88
89 /*
90 * Perform error checking
91 */
92 CKTcircuit *ckt;
93 {
94 PZAN *pzan = (PZAN *) ckt->CKTcurJob;
95 int i;
96
97 if ((i = CKTtypelook("transmission line")) != -1 &&
98 ckt->CKThead[i] != NULL)
99 ERROR(E_XMISSIONLINE, "Transmission lines not supported")
100
101 pzan->PZpoleList = (PZtrial *) NULL;
102 pzan->PZzeroList = (PZtrial *) NULL;
103 pzan->PZnPoles = 0;
104 pzan->PZnZeros = 0;
105
106 if (pzan->PZin_pos == pzan->PZin_neg)
107 ERROR(E_SHORT, "Input is shorted")
108
109 if (pzan->PZout_pos == pzan->PZout_neg)
110 ERROR(E_SHORT, "Output is shorted")
111
112 if (pzan->PZin_pos == pzan->PZout_pos
113 && pzan->PZin_neg == pzan->PZout_neg
114 && pzan->PZinput_type == PZ_IN_VOL)
115 ERROR(E_INISOUT, "Transfer function is unity")
116 else
117 if (pzan->PZin_pos == pzan->PZout_neg
118 && pzan->PZin_neg == pzan->PZout_pos
119 && pzan->PZinput_type == PZ_IN_VOL)
120 ERROR(E_INISOUT, "Transfer function is -1")
121
122 return (OK);
123 }
124
125
126 static int
PZpost(ckt)127 PZpost(ckt)
128
129 /*
130 * PZpost Post-processing of the pole-zero analysis results
131 */
132 CKTcircuit *ckt;
133 {
134 PZAN *pzan = (PZAN *) ckt->CKTcurJob;
135 GENERIC *pzPlotPtr = NULL; /* the plot pointer for front end */
136 IFcomplex *out_list;
137 IFvalue outData; /* output variable (points to out_list) */
138 IFuid *namelist;
139 PZtrial *root;
140 char name[50];
141 int i, j;
142 struct sOUTdata outd;
143
144 namelist = (IFuid *) MALLOC((pzan->PZnPoles
145 + pzan->PZnZeros)*sizeof(IFuid));
146 out_list = (IFcomplex *)MALLOC((pzan->PZnPoles
147 + pzan->PZnZeros)*sizeof(IFcomplex));
148
149 j = 0;
150 for (i = 0; i < pzan->PZnPoles; i++) {
151 sprintf(name, "pole(%-u)", i+1);
152 (*(SPfrontEnd->IFnewUid))(ckt,&(namelist[j++]),(IFuid)NULL,
153 name,UID_OTHER,(GENERIC **)NULL);
154 }
155 for (i = 0; i < pzan->PZnZeros; i++) {
156 sprintf(name, "zero(%-u)", i+1);
157 (*(SPfrontEnd->IFnewUid))(ckt,&(namelist[j++]),(IFuid)NULL,
158 name,UID_OTHER,(GENERIC **)NULL);
159 }
160
161 outd.circuitPtr = (GENERIC *)ckt;
162 outd.analysisPtr = (GENERIC*)pzan;
163 outd.analName = pzan->JOBname;
164 outd.refName = (IFuid)NULL;
165 outd.refType = (int)0;
166 outd.numNames = pzan->PZnPoles + pzan->PZnZeros;
167 outd.dataNames = namelist;
168 outd.dataType = IF_COMPLEX;
169 outd.plotPtr = &pzPlotPtr;
170 outd.numPts = 1;
171 outd.initValue = 0;
172 outd.finalValue = 0;
173 outd.step = 0;
174 (*SPfrontEnd->OUTbeginPlot)((GENERIC*)&outd);
175
176 j = 0;
177 if (pzan->PZnPoles > 0) {
178 for (root = pzan->PZpoleList; root != NULL; root = root->next) {
179 for (i = 0; i < root->multiplicity; i++) {
180 out_list[j].real = root->s.real;
181 out_list[j].imag = root->s.imag;
182 j += 1;
183 if (root->s.imag != 0.0) {
184 out_list[j].real = root->s.real;
185 out_list[j].imag = -root->s.imag;
186 j += 1;
187 }
188 }
189 DEBUG printf("LIST pole: (%g,%g) x %d\n",
190 root->s.real, root->s.imag, root->multiplicity);
191 }
192 }
193
194 if (pzan->PZnZeros > 0) {
195 for (root = pzan->PZzeroList; root != NULL; root = root->next) {
196 for (i = 0; i < root->multiplicity; i++) {
197 out_list[j].real = root->s.real;
198 out_list[j].imag = root->s.imag;
199 j += 1;
200 if (root->s.imag != 0.0) {
201 out_list[j].real = root->s.real;
202 out_list[j].imag = -root->s.imag;
203 j += 1;
204 }
205 }
206 DEBUG printf("LIST zero: (%g,%g) x %d\n",
207 root->s.real, root->s.imag, root->multiplicity);
208 }
209 }
210
211 outData.v.numValue = pzan->PZnPoles + pzan->PZnZeros;
212 outData.v.vec.cVec = out_list;
213
214 (*SPfrontEnd->OUTdata)(pzPlotPtr, (IFvalue *) 0, &outData);
215 (*(SPfrontEnd->OUTendPlot))(pzPlotPtr);
216
217 FREE(out_list);
218 FREE(namelist);
219
220 return(OK);
221 }
222
223
224 int
CKTpzSetup(ckt,type)225 CKTpzSetup(ckt, type)
226
227 /* CKTpzSetup(ckt)
228 * iterate through all the various
229 * pzSetup functions provided for the circuit elements in the
230 * given circuit, setup ...
231 */
232 CKTcircuit *ckt;
233 int type;
234 {
235 extern SPICEdev *DEVices[];
236 PZAN *pzan = (PZAN *) ckt->CKTcurJob;
237 SMPmatrix *matrix;
238 int error;
239 int /*i,*/ temp, solution_col, balance_col;
240 int input_pos, input_neg, output_pos, output_neg;
241 struct sCKTmodHead *mh;
242 int (*func)();
243
244 NIdestroy(ckt);
245 error = NIinit(ckt);
246 if (error)
247 return(error);
248 matrix = ckt->CKTmatrix;
249
250 /* Really awful . . . */
251 ckt->CKTnumStates = 0;
252
253 for (mh = ckt->CKTheadList; mh != NULL; mh = mh->next) {
254 if ((func = DEVices[mh->type]->DEVpzSetup) != NULL) {
255 error = (*func)(matrix, mh->head,ckt,&ckt->CKTnumStates);
256 if (error)
257 return(error);
258 }
259 }
260
261 solution_col = 0;
262 balance_col = 0;
263
264 input_pos = pzan->PZin_pos;
265 input_neg = pzan->PZin_neg;
266
267 if (type == PZ_DO_ZEROS) {
268 /* Vo/Ii in Y */
269 output_pos = pzan->PZout_pos;
270 output_neg = pzan->PZout_neg;
271 }
272 else if (pzan->PZinput_type == PZ_IN_VOL) {
273 /* Vi/Ii in Y */
274 output_pos = pzan->PZin_pos;
275 output_neg = pzan->PZin_neg;
276 }
277 else {
278 /* Denominator */
279 output_pos = 0;
280 output_neg = 0;
281 input_pos = 0;
282 input_neg = 0;
283 }
284
285 if (output_pos) {
286 solution_col = output_pos;
287 if (output_neg)
288 balance_col = output_neg;
289 }
290 else {
291 solution_col = output_neg;
292 temp = input_pos;
293 input_pos = input_neg;
294 input_neg = temp;
295 }
296
297 if (input_pos)
298 pzan->PZdrive_pptr = spGetElement(matrix, input_pos, solution_col);
299 else
300 pzan->PZdrive_pptr = NULL;
301
302 if (input_neg)
303 pzan->PZdrive_nptr = spGetElement(matrix, input_neg, solution_col);
304 else
305 pzan->PZdrive_nptr = NULL;
306
307 pzan->PZsolution_col = solution_col;
308 pzan->PZbalance_col = balance_col;
309
310 pzan->PZnumswaps = 1;
311
312 error = NIreinit(ckt);
313 if (error)
314 return (error);
315
316 return (OK);
317 }
318