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