1 /**********
2 Copyright 1990 Regents of the University of California. All rights reserved.
3 **********/
4
5 #include "ngspice/ngspice.h"
6 #include "ngspice/complex.h"
7 #include "ngspice/cktdefs.h"
8 #include "ngspice/smpdefs.h"
9 #include "ngspice/pzdefs.h"
10 #include "ngspice/trandefs.h" /* only to get the 'mode' definitions */
11 #include "ngspice/sperror.h"
12
13
14 #define DEBUG if (0)
15
16 /* ARGSUSED */
17 int
PZan(CKTcircuit * ckt,int reset)18 PZan(CKTcircuit *ckt, int reset)
19 {
20 PZAN *job = (PZAN *) ckt->CKTcurJob;
21
22 int error;
23 int numNames;
24 IFuid *nameList;
25 runDesc *plot = NULL;
26
27 NG_IGNORE(reset);
28
29 error = PZinit(ckt);
30 if (error != OK) return error;
31
32 /* Calculate small signal parameters at the operating point */
33 error = CKTop(ckt, (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITJCT,
34 (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT,
35 ckt->CKTdcMaxIter);
36 if (error)
37 return(error);
38
39 ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG;
40 error = CKTload(ckt); /* Make sure that all small signal params are
41 * set */
42 if (error)
43 return(error);
44
45 if (ckt->CKTkeepOpInfo) {
46 /* Dump operating point. */
47 error = CKTnames(ckt,&numNames,&nameList);
48 if(error) return(error);
49 error = SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob,
50 "Distortion Operating Point",
51 NULL, IF_REAL,
52 numNames, nameList, IF_REAL,
53 &plot);
54 if(error) return(error);
55 CKTdump(ckt, 0.0, plot);
56 SPfrontEnd->OUTendPlot (plot);
57 }
58
59 if (job->PZwhich & PZ_DO_POLES) {
60 error = CKTpzSetup(ckt, PZ_DO_POLES);
61 if (error != OK)
62 return error;
63 error = CKTpzFindZeros(ckt, &job->PZpoleList, &job->PZnPoles);
64 if (error != OK)
65 return(error);
66 }
67
68 if (job->PZwhich & PZ_DO_ZEROS) {
69 error = CKTpzSetup(ckt, PZ_DO_ZEROS);
70 if (error != OK)
71 return error;
72 error = CKTpzFindZeros(ckt, &job->PZzeroList, &job->PZnZeros);
73 if (error != OK)
74 return(error);
75 }
76
77 return PZpost(ckt);
78 }
79
80 /*
81 * Perform error checking
82 */
83
84 int
PZinit(CKTcircuit * ckt)85 PZinit(CKTcircuit *ckt)
86 {
87 PZAN *job = (PZAN *) ckt->CKTcurJob;
88 int i;
89
90 i = CKTtypelook("transmission line");
91 if (i == -1) {
92 i = CKTtypelook("Tranline");
93 if (i == -1)
94 i = CKTtypelook("LTRA");
95 }
96 if (i != -1 && ckt->CKThead[i] != NULL)
97 MERROR(E_XMISSIONLINE, "Transmission lines not supported");
98
99 job->PZpoleList = NULL;
100 job->PZzeroList = NULL;
101 job->PZnPoles = 0;
102 job->PZnZeros = 0;
103
104 if (job->PZin_pos == job->PZin_neg)
105 MERROR(E_SHORT, "Input is shorted");
106
107 if (job->PZout_pos == job->PZout_neg)
108 MERROR(E_SHORT, "Output is shorted");
109
110 if (job->PZin_pos == job->PZout_pos
111 && job->PZin_neg == job->PZout_neg
112 && job->PZinput_type == PZ_IN_VOL)
113 MERROR(E_INISOUT, "Transfer function is unity");
114 else if (job->PZin_pos == job->PZout_neg
115 && job->PZin_neg == job->PZout_pos
116 && job->PZinput_type == PZ_IN_VOL)
117 MERROR(E_INISOUT, "Transfer function is -1");
118
119 return(OK);
120 }
121
122 /*
123 * PZpost Post-processing of the pole-zero analysis results
124 */
125
126 int
PZpost(CKTcircuit * ckt)127 PZpost(CKTcircuit *ckt)
128 {
129 PZAN *job = (PZAN *) ckt->CKTcurJob;
130 runDesc *pzPlotPtr = NULL; /* the plot pointer for front end */
131 IFcomplex *out_list;
132 IFvalue outData; /* output variable (points to out_list) */
133 IFuid *namelist;
134 PZtrial *root;
135 char name[50];
136 int i, j;
137
138 namelist = TMALLOC(IFuid, job->PZnPoles + job->PZnZeros);
139 out_list = TMALLOC(IFcomplex, job->PZnPoles + job->PZnZeros);
140
141 j = 0;
142 for (i = 0; i < job->PZnPoles; i++) {
143 sprintf(name, "pole(%-u)", i+1);
144 SPfrontEnd->IFnewUid (ckt, &(namelist[j++]), NULL, name, UID_OTHER, NULL);
145 }
146 for (i = 0; i < job->PZnZeros; i++) {
147 sprintf(name, "zero(%-u)", i+1);
148 SPfrontEnd->IFnewUid (ckt, &(namelist[j++]), NULL, name, UID_OTHER, NULL);
149 }
150
151 SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob,
152 ckt->CKTcurJob->JOBname,
153 NULL, 0,
154 job->PZnPoles + job->PZnZeros, namelist, IF_COMPLEX,
155 &pzPlotPtr);
156
157 j = 0;
158 if (job->PZnPoles > 0) {
159 for (root = job->PZpoleList; root != NULL; root = root->next) {
160 for (i = 0; i < root->multiplicity; i++) {
161 out_list[j].real = root->s.real;
162 out_list[j].imag = root->s.imag;
163 j += 1;
164 if (root->s.imag != 0.0) {
165 out_list[j].real = root->s.real;
166 out_list[j].imag = -root->s.imag;
167 j += 1;
168 }
169 }
170 DEBUG printf("LIST pole: (%g,%g) x %d\n",
171 root->s.real, root->s.imag, root->multiplicity);
172 }
173 }
174
175 if (job->PZnZeros > 0) {
176 for (root = job->PZzeroList; root != NULL; root = root->next) {
177 for (i = 0; i < root->multiplicity; i++) {
178 out_list[j].real = root->s.real;
179 out_list[j].imag = root->s.imag;
180 j += 1;
181 if (root->s.imag != 0.0) {
182 out_list[j].real = root->s.real;
183 out_list[j].imag = -root->s.imag;
184 j += 1;
185 }
186 }
187 DEBUG printf("LIST zero: (%g,%g) x %d\n",
188 root->s.real, root->s.imag, root->multiplicity);
189 }
190 }
191
192 outData.v.numValue = job->PZnPoles + job->PZnZeros;
193 outData.v.vec.cVec = out_list;
194
195 SPfrontEnd->OUTpData (pzPlotPtr, NULL, &outData);
196 SPfrontEnd->OUTendPlot (pzPlotPtr);
197
198 return(OK);
199 }
200